Tusiapedia
tusiapediawiki
https://tusiapedia.miraheze.org/wiki/Main_Page
MediaWiki 1.40.2
first-letter
Media
Special
Talk
User
User talk
Tusiapedia
Tusiapedia talk
File
File talk
MediaWiki
MediaWiki talk
Template
Template talk
Help
Help talk
Category
Category talk
Module
Module talk
Template:T
10
59
116
2016-09-06T23:14:40Z
star>Alistair3149
0
Protected "[[Template:T]]": Completed template, changes can be proposed in the talk page ([Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite))
wikitext
text/x-wiki
<includeonly><nowiki>{{</nowiki>[[Template:{{{1}}}|{{{1}}}]]{{t/piece|{{{2|---}}}}}{{t/piece|{{{3|---}}}}}{{t/piece|{{{4|---}}}}}{{t/piece|{{{5|---}}}}}{{t/piece|{{{6|---}}}}}{{t/piece|{{{7|---}}}}}{{t/piece|{{{8|---}}}}}{{t/piece|{{{9|---}}}}}{{t/piece|{{{10|---}}}}}{{t/piece|{{{11|---}}}}}{{t/piece|{{{12|---}}}}}{{t/piece|{{{13|---}}}}}{{t/piece|{{{14|---}}}}}{{t/piece|{{{15|---}}}}}{{t/piece|{{{16|---}}}}}{{t/piece|{{{17|---}}}}}{{t/piece|{{{18|---}}}}}{{t/piece|{{{19|---}}}}}{{t/piece|{{{20|---}}}}}{{t/piece|{{{21|---}}}}}<nowiki>}}</nowiki></includeonly><noinclude>
{{documentation}}</noinclude>
9bbfbb3d891ffa62ccebed3d5790ccf39d59c793
Category:Article management templates
14
4
6
2017-03-31T21:26:53Z
Star>Alistair3149
0
wikitext
text/x-wiki
A list of article management templates
[[Category:Templates]]
11b8b439968d60cbb1df76388c0e1e9b122ad13c
Category:File management templates
14
10
18
2017-03-31T21:27:26Z
Star>Alistair3149
0
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Citation templates
14
7
12
2017-03-31T21:29:04Z
Star>Alistair3149
0
Created page with "[[Category:Templates]]"
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:General wiki templates
14
12
22
2017-03-31T21:32:04Z
Star>Alistair3149
0
Created page with "[[Category:Templates]]"
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Infobox Templates
14
15
28
2017-03-31T21:32:56Z
Star>Alistair3149
0
wikitext
text/x-wiki
See [[Help:Infoboxes]]
[[Category:Templates]]
50fb8af8e4d62b8e888bb9246e15a1806c52b2b5
Category:Mathematical function templates
14
24
46
2017-04-26T22:37:58Z
Star>Alistair3149
0
Created page with "[[Category:Templates]]"
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Typing-aid templates
14
35
68
2017-04-27T22:33:25Z
Star>Alistair3149
0
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Formatting and function templates
14
11
20
2017-04-27T23:10:59Z
Star>Alistair3149
0
Created page with "[[Category:Templates]]"
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Internal link templates
14
18
34
2017-04-27T23:24:07Z
Star>Alistair3149
0
Created page with "[[Category:Templates]]"
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Template:Nbsp
10
44
86
2017-04-27T23:27:42Z
Star>Alistair3149
0
Redirected page to [[Template:Spaces]]
wikitext
text/x-wiki
#REDIRECT [[Template:Spaces]]
d55076009c86bad01caacd67c545037409e5e1ee
Category:String manipulation templates
14
31
60
2017-06-03T16:34:09Z
Star>Alistair3149
0
Created page with "[[Category:Templates]]"
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Manual templates
14
23
44
2017-06-15T21:41:20Z
Star>Alistair3149
0
Alistair3149 moved page [[Category:Live templates]] to [[Category:Manual templates]]
wikitext
text/x-wiki
Below are WIP templates that require manual update frequently as of now, and they are pending to be automated in the future.
[[Category:Templates]]
6b82ad760e14f78fdd70dc3f3d47ab254e57ff36
Category:SEO templates
14
29
56
2017-06-19T03:29:57Z
Star>Alistair3149
0
wikitext
text/x-wiki
One of these templates should be included in all page in the main namespace
[[Category:Templates]]
0a8943c2a2dbff16b4685086e66c2086c7d39367
Category:Vehicle Specification Templates
14
38
74
2017-11-01T19:19:06Z
Star>Alistair3149
0
added category
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Substitution only templates
14
32
62
2017-11-01T19:35:10Z
Star>Alistair3149
0
Created page with "[[Category:Templates]]"
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Audio templates
14
5
8
2018-06-02T05:16:24Z
Star>Alistair3149
0
Created page with "[[Category:Templates]]"
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:I18n templates
14
14
26
2019-12-08T19:56:48Z
Star>Alistair3149
0
Cleaned up translation residue
wikitext
text/x-wiki
'''I18n templates''' are templates contain repetitive words used in the whole wiki. The following templates help to reduce redundancy in translations and also serve as the standard translation for frequently used words.
[[Category:Templates]]
7717381b16fc84d004cf6f5bdaa73fa9febd0b07
Category:Language templates
14
19
36
2019-12-08T22:59:13Z
Star>Alistair3149
0
Created page with "[[Category:Templates]]"
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:DPL templates
14
8
14
2020-03-12T23:04:47Z
Star>Alistair3149
0
wikitext
text/x-wiki
This category contains templates which are designed solely for use with [https://help.gamepedia.com/Extension:DPL3/Manual DynamicPageList3].
For all page that uses DPL calls, see [[Special:WhatLinksHere/Template:Extension DPL]].
[[Category:Templates]]
2bb614cfa9d61ac951d5b671ebaa9bfbbd6fed0c
Category:Lua-based templates
14
20
38
2020-03-15T08:59:34Z
Star>Alistair3149
0
Created page with "[[Category:Templates]]"
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Under-construction templates
14
36
70
2020-03-17T19:54:09Z
Star>Alistair3149
0
1 revision imported
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Alien language templates
14
3
4
2020-03-17T19:54:36Z
Star>Alistair3149
0
1 revision imported
wikitext
text/x-wiki
This category contains templates related displaying alien languages in article.
[[Category:Templates]]
31028d351947fb2c12f3d3976ef9be10d8ccdd76
Category:Infobox templates
14
16
30
2020-03-17T19:54:36Z
Star>Alistair3149
0
1 revision imported
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Maintenance templates
14
22
42
2020-03-17T19:54:36Z
Star>Alistair3149
0
1 revision imported
wikitext
text/x-wiki
This category contains templates related to ones that are used in articles that require maintenance.
[[Category:Templates]]
258ee9e751f38daed5ebb5a2281fa0f03311d340
Category:Templates imported from Wikipedia
14
33
64
2020-03-17T19:54:36Z
Star>Alistair3149
0
1 revision imported
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Vehicle specification templates
14
39
76
2020-03-17T19:54:36Z
Star>Alistair3149
0
1 revision imported
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Template:Spaces
10
45
88
2020-03-17T20:29:07Z
Star>Alistar Bot
0
/* top */Hygiene, replaced: {{documentation}} → {{/doc}}
wikitext
text/x-wiki
<span class="nowrap">{{#iferror:{{#expr:{{{1|1}}}}}
|{{#switch:{{{1}}}
|fig= 
|en= 
|em= 
|thin= 
|hair= 
|
}}
|{{#invoke:String|rep|{{#switch:{{{2}}}
|fig= 
|en= 
|em= 
|thin= 
|hair= 
|
}}|{{{1|1}}}}}
}}</span><noinclude>
{{/doc}}
</noinclude>
17efb36433f45a5c4f23528902387edcf0e174f0
Template:T/piece
10
60
118
2020-03-17T20:33:48Z
star>Alistar Bot
0
/* top */Hygiene, replaced: {{documentation}} → {{/doc}}
wikitext
text/x-wiki
{{#ifeq: {{{1|---}}}|---|||<font color="gray">''<{{{1}}}>''</font>}}<noinclude>
{{/doc}}</noinclude>
2ddf7df2334b2a1624bf213ade67ba6b68296e86
Template:Documentation
10
52
102
2020-03-19T00:32:09Z
star>Alistair3149
0
wikitext
text/x-wiki
<includeonly>{{#invoke:Documentation|doc}}__NOEDITSECTION__{{#seo:
|type = website
|description = {{FULLPAGENAME}} is a template page used on the Star Citizen Wiki. Templates are pages that are embedded (transcluded) into other pages to allow for the repetition of information.
|site_name = Star Citizen Wiki
|locale = {{PAGELANGUAGE}}
}}</includeonly><noinclude>{{/doc}}</noinclude>
2690a5347936db4ace54fe94a0b3092b6bb04a37
Category:Utility templates
14
37
72
2020-04-25T07:48:02Z
Star>Alistair3149
0
wikitext
text/x-wiki
{{Category header|templates|that are not suitable to use directly on pages. They should only be used in templates|related=no}}
[[Category:Templates]]
8ef6eadc680eea4f36a48b5fbf988cab1768b2ef
Category:Interface message templates
14
17
32
2020-06-25T09:43:05Z
Star>Alistair3149
0
Created page with "{{Category header|templates|MediaWiki interface messages}} [[Category:Templates]]"
wikitext
text/x-wiki
{{Category header|templates|MediaWiki interface messages}}
[[Category:Templates]]
2ceb3a9c4b6b1e027d79edc01030738d73250add
Category:Number templates
14
26
50
2021-03-30T02:16:36Z
Star>Alistair3149
0
Created page with "{{Category header|templates|manipulate number string}} [[Category:Templates]]"
wikitext
text/x-wiki
{{Category header|templates|manipulate number string}}
[[Category:Templates]]
8767a5b6f92ac0662e9e3feae33c87ecc776d542
Category:Numerical conversion templates
14
27
52
2021-03-30T02:16:59Z
Star>Alistair3149
0
Created page with "{{Category header|templates|convert numbers}} [[Category:Templates]]"
wikitext
text/x-wiki
{{Category header|templates|convert numbers}}
[[Category:Templates]]
8d11e0ccdfed85c0343603873eb362298ca75a25
Module:DPLlua
828
54
106
2021-05-09T04:14:59Z
star>Alistair3149
0
Sync with RS wiki
Scribunto
text/plain
-- <nowiki>
local dpl = {}
local libraryUtil = require( 'libraryUtil' )
local hasContent = require( 'Module:Paramtest' ).has_content
local checkType = libraryUtil.checkType
local checkTypeForNamedArg = libraryUtil.checkTypeForNamedArg
dpl.pipe = '¦'
local dataContentMarker = '`#@@#`'
local allIncludedParamNames = {}
-- Custom function for splitting a string because mw.text.split() is waaay too slow
local function split( str, pattern, plain )
local res = {}
local continue = true
local startIndex = 1
while continue do
local i, j = string.find( str, pattern, startIndex, plain )
if i then
table.insert( res, string.sub( str, startIndex, i-1 ) )
startIndex = j + 1
else
table.insert( res, string.sub( str, startIndex ) )
continue = false
end
end
return res
end
-- Also custom function for speed
local function trim( str )
return (string.gsub( str, '^%s+', '' ):gsub( '%s+$', '' ))
end
local function mergeItem( tbl, key, item )
if type( tbl[key] ) == 'table' and type( item ) == 'table' then
for k in pairs( tbl[key] ) do
mergeItem( tbl[key], k, item[k] )
end
elseif type( tbl[key] ) == 'table' then
table.insert( tbl[key], item )
else
tbl[key] = { tbl[key], item }
end
end
local escapeChars = {
['{'] = '{',
['}'] = '}',
['['] = '[',
[']'] = ']',
['|'] = '|',
['-'] = '‐'
}
local function escape( str )
return (string.gsub( str, '[{}%[%]|%-]', escapeChars ))
end
local unEscapeChars = {
['{'] = '{',
['}'] = '}',
['['] = '[',
[']'] = ']',
['|'] = '|',
['‐'] = '-'
}
local function unEscape( str )
return (string.gsub( str, '&#%d+;', unEscapeChars ))
end
local function fixCurlyBrackets( str )
-- the \226\157\180\181 are used to match ❴ (U+2774) and ❵ (U+2775) wich are 3 bytes long (UTF-8) so
-- we can't use them directly inside [] patterns. Ustring would fix this but it's way too slow.
return (string.gsub( str, '\226\157[\180\181]', { ['❴'] = '{', ['❵'] = '}' } ))
end
local function removeFormattingSettings( query )
local toRemove = {
'mode',
'table',
'tablerow',
'tablesortcol',
'headingmode',
'headingcount',
'listattr',
'itemattr',
'hlistattr',
'hitemattr',
'userdateformat',
'shownamespace',
'escapelinks',
'titlemaxlength',
'replaceintitle',
'columns',
'rows',
'rowsize',
'rowcolformat',
'resultsheader',
'resultsfooter',
'oneresultheader',
'oneresultfooter',
'noresultsheader',
'suppresserrors',
'noresultsfooter',
'format',
'groupMultiTemplateResults'
}
for _, k in ipairs( toRemove ) do
query[k] = nil
end
end
local function formatInclude( query )
checkTypeForNamedArg( 'Module:DPLlua.ask', 'include', query, 'string' )
query = split( query, ',', true )
local includedParamNames = {}
local sectionAttributes = {}
for i = 1, #query do
if query[i]:match( '%b{}' ) then -- Check if we are including a template
local templateName, extra = query[i]:match( '{(.-)[¦|}](.*)' )
if hasContent( extra ) then
local phantomTemplateName = extra:match( '^(.-)}' ) or extra:match( '^[./].+' )
local phantomTemplatePrefix = extra:match( '^(.-)}' ) and '' or templateName
local params = extra:gsub( '^.-}', '' ):gsub( '^[./].+', '' ):gsub( ':%-', '' )
local sur = hasContent( phantomTemplateName ) and ('¦' .. phantomTemplatePrefix .. phantomTemplateName) or ''
query[i] = string.format( '{%s%s}%s', templateName, sur, params )
if hasContent( phantomTemplateName ) then
table.insert( includedParamNames, { name=phantomTemplatePrefix..phantomTemplateName, isTemplate=true, hasPhantomTemplate=true } )
table.insert( sectionAttributes, { hasPhantomTemplate=true } )
else
for param in params:gmatch( ':([^:]*)' ) do
param = trim( param )
table.insert( includedParamNames, { name=templateName, isTemplate=true, param=param } )
end
table.insert( sectionAttributes, { hasPhantomTemplate=false } )
end
else
query[i] = string.format( '{%s¦DPLlua helper}', templateName ) -- Use a helper template to get all the parameters of our included template
table.insert( includedParamNames, { name=templateName, isTemplate=true, includeAll=true } )
table.insert( sectionAttributes, { hasPhantomTemplate=false } )
end
else
table.insert( includedParamNames, { name=trim( query[i] ) } )
table.insert( sectionAttributes, { hasPhantomTemplate=false } )
end
end
return table.concat( query, ',' ), includedParamNames, sectionAttributes
end
local function formatDpl( query )
local queries = {}
local count = query.count or 500
local offset = query.offset or 0
local usesInclude = false
local includedParamNames = {}
local sectionAttributes
query.count = nil
query.offset = nil
-- Use table format so we can place dataContentMarkers around each included parameter. The secseparator
-- is needed to add dataContentMarkers when a phantom template is used
local dplStringInclude =
[=[
{{#dpl:
|noresultsheader=@@
|count=%s
|offset=%s
|%s
|table=,
|listseparators=,\n¦-\n¦[[%%PAGE%%¦]],,
|tablerow=%s
|secseparators=%s
}}]=]
-- Table format requires an include statement so we use format instead.
-- This is also a lot faster than adding an empty include statement
local dplStringNoInclude =
[=[
{{#dpl:
|noresultsheader=@@
|count=%s
|offset=%s
|%s
|format=,¦-¦[[%%PAGE%%¦]],,
}}]=]
-- Auto generate more than one dpl if count > 500
-- The results of these are later combined
for i = 1, math.ceil( count / 500 ) do
local params = {}
for k, v in pairs( query ) do
if k == 'include' then
v, includedParamNames, sectionAttributes = formatInclude( v )
usesInclude = true
end
if type( v ) == 'table' then
for _, x in ipairs( v ) do
table.insert( params, k .. '=' .. tostring( x ):gsub( '|', '¦' ) )
end
else
table.insert( params, k .. '=' .. tostring( v ):gsub( '|', '¦' ) )
end
end
if usesInclude then
local secseparators = ''
for _, v in ipairs( sectionAttributes ) do
if v.hasPhantomTemplate then
-- Phantom templates need this because they ignore tablerow formatting
secseparators = secseparators .. '¶¦' .. dataContentMarker .. ',' .. dataContentMarker .. ','
else
secseparators = secseparators .. '¶¦,,'
end
end
table.insert( queries, string.format(
dplStringInclude,
count > 500 and 500 or count,
offset,
table.concat( params, '\n|' ),
string.rep( dataContentMarker..'%%'..dataContentMarker..',', #includedParamNames ),
secseparators
) )
else
table.insert( queries, string.format(
dplStringNoInclude,
count > 500 and 500 or count,
offset,
table.concat( params, '\n|' )
) )
end
count = count - 500
offset = offset + 500
end
table.insert( allIncludedParamNames, includedParamNames )
return table.concat( queries )
end
local function toTable( query, groupMultiTemplateResults )
local includedParamNames = table.remove( allIncludedParamNames, 1 )
local usesInclude = #includedParamNames > 0
local res = {}
query = query:gsub( '<p>Extension:DynamicPageList .-</p>', function(item) res.error = item; return '' end )
if query:find( '^@@' ) then -- @@ is used when no result is found
return res
end
if usesInclude then
query = query:gsub( dataContentMarker..'(.-)'..dataContentMarker, escape )
end
query = trim( query )
query = split( query, '|-', true ) -- Results of the returned pages are separated by |-
for _, v in ipairs( query ) do
if hasContent( v ) and not v:find( '^@@' ) then
v = trim( v )
local title = v:match( '^|%[%[(.-)|' )
local rawDataList = v:match( '^|.-|.-|(.*)' ) -- This is everything after the title
if not usesInclude then
if title and title ~= '' then
table.insert( res, title )
end
else
-- When multiple includes are used (e.g. include={Template1},{Template2} or include={Template}:1:2) their results are separated by a pipe
rawDataList = split( rawDataList, '|', true )
local cleanedDataList = {}
for _incIndex, dataItem in ipairs( rawDataList ) do
local incIndex = ((_incIndex - 1) % #includedParamNames) + 1 -- Needed in case the same template appears multiple times on the same page
dataItem = unEscape( dataItem )
dataItem = trim( dataItem )
if includedParamNames[ incIndex ].isTemplate and includedParamNames[ incIndex ].includeAll then -- Check if we included a full template
-- When we include an entire template we use the %ARGS% parameter supplied by dpl.
-- However all | characters are repaced with §, e.g.:
-- §namelessParam
-- §param = text [[wowee§link text]]
-- §param2 = text {{something§something else}}
dataItem = dataItem:gsub( '\127\'"`UNIQ%-%-nowiki%-%x+%-QINU`"\'\127', function(item) return '<nowiki>' .. item .. '</nowiki>' end )
dataItem = mw.text.unstripNoWiki( dataItem ) -- Unstrip nowiki so we can clean their content
dataItem = fixCurlyBrackets( dataItem ) -- When using the %ARGS% dpl parameter, curly brackets are replaced with ❴ (U+2774) and ❵ (U+2775)
dataItem = dataItem:gsub( '%b{}', function(x) return x:gsub( '§', '|' ) end ) -- Restore pipe characters inside links and templates
dataItem = dataItem:gsub( '%b[]', function(x) return x:gsub( '§', '|' ) end )
dataItem = dataItem:gsub( '<nowiki>(.-)</nowiki>', function(x) return mw.getCurrentFrame():extensionTag( 'nowiki', x ) end ) -- Restrip nowiki
local _dataItem = {}
if dataItem ~= '' then
dataItem = split( dataItem:sub( 3 ), '§' ) -- The sub(3) removes the first § at the start. § is 2 bytes wide so start at index 3
for i, item in ipairs( dataItem ) do
if item:find( '=' ) then -- Check if the parameter is named or unnamed
local param, value = item:match( '^%s*(.-)%s*=%s*(.-)%s*$' )
_dataItem[ param ] = value
else
table.insert( _dataItem, trim( item ) )
end
end
end
dataItem = _dataItem
end
local dataListIndex = groupMultiTemplateResults and 1 or math.ceil( _incIndex / #includedParamNames )
if
includedParamNames[ incIndex ].isTemplate and
not includedParamNames[ incIndex ].includeAll and
not includedParamNames[ incIndex ].hasPhantomTemplate
then -- This means there was an include in the form 'include = {template}:param'
local templateName = includedParamNames[ incIndex ].name
local paramName = includedParamNames[ incIndex ].param
paramName = tonumber( paramName ) or paramName -- Keep as string if tonumber fails
cleanedDataList[ dataListIndex ] = cleanedDataList[ dataListIndex ] or {}
cleanedDataList[ dataListIndex ][ templateName ] = cleanedDataList[ dataListIndex ][ templateName ] or {}
if groupMultiTemplateResults and _incIndex > #includedParamNames then
mergeItem( cleanedDataList[ dataListIndex ][ templateName ], paramName, dataItem )
else
cleanedDataList[ dataListIndex ][ templateName ][ paramName ] = dataItem
end
else
local templateName = includedParamNames[ incIndex ].name
cleanedDataList[ dataListIndex ] = cleanedDataList[ dataListIndex ] or {}
if groupMultiTemplateResults and _incIndex > #includedParamNames then
mergeItem( cleanedDataList[ dataListIndex ], templateName, dataItem )
else
cleanedDataList[ dataListIndex ][ templateName ] = dataItem
end
end
end
if title and title ~= '' then
for _, v in ipairs( cleanedDataList ) do
table.insert( res, { title=title, include=v } )
end
end
end
end
end
return res
end
-- Accepts a series of tables each containig the settings for a dpl query.
-- Combinig multiple dpl queries yields better performance than doing them sequentially
function dpl.ask( ... )
local formatTime = os.clock()
local queries = { ... }
local wantsGrouping = {}
for i = 1, #queries do
checkType( 'Module:DPLlua.ask', i, queries[i], 'table' )
table.insert( wantsGrouping, queries[i].groupMultiTemplateResults or false )
removeFormattingSettings( queries[i] )
queries[i] = formatDpl( queries[i] )
end
formatTime = os.clock() - formatTime
local DPLtime = os.clock()
queries = table.concat( queries, '$@µ@$' )
queries = mw.getCurrentFrame():preprocess( queries )
queries = split( queries, '$@µ@$', true )
DPLtime = os.clock() - DPLtime
for i = 1, #queries do
local parseTime = os.clock()
queries[i] = toTable( queries[i], wantsGrouping[i] )
parseTime = os.clock() - parseTime
queries[i]['DPL time'] = DPLtime
queries[i]['Parse time'] = math.floor( (formatTime + parseTime) * 1e5 ) / 1e5 -- os.clock() has a resolution of 10µs
end
return unpack( queries )
end
-- function dpl.test()
-- local time = os.clock()
-- local a, b = dpl.ask({
-- namespace = 'Module',
-- linksto = 'Module:Chart data',
-- distinct = 'strict',
-- ordermethod = 'title',
-- nottitlematch = '%/doc¦%sandbox%¦Exchange/%¦Exchange historical/%¦Chart data',
-- ignorecase = 'true',
-- allowcachedresults = false
-- },{
-- namespace = 'Module',
-- linksto = 'Module:Enum',
-- distinct = 'strict',
-- ordermethod = 'title',
-- nottitlematch = '%/doc¦%sandbox%¦Exchange/%¦Exchange historical/%¦Enum',
-- ignorecase = 'true',
-- allowcachedresults = false
-- })
-- mw.logObject(a)
-- mw.logObject(b)
-- local a, b = dpl.ask({
-- namespace = 'Module',
-- linksto = 'Module:Chart data',
-- distinct = 'strict',
-- ordermethod = 'title',
-- nottitlematch = '%/doc¦%sandbox%¦Exchange/%¦Exchange historical/%¦Chart data',
-- ignorecase = 'true',
-- allowcachedresults = false
-- },{
-- namespace = '',
-- ignorecase = 'true',
-- uses = 'Template:Infobox Recipe',
-- count = 50,
-- include = '{Infobox Recipe},{Infobox Item}',
-- allowcachedresults = false
-- })
-- mw.logObject(a)
-- mw.logObject(b)
-- local a = dpl.ask{
-- namespace = '',
-- uses = 'Template:Infobox Recipe',
-- include = '{Infobox Recipe}:skill:name,{Infobox Item}:update,{Infobox Item|test}',
-- count = 50,
-- ordermethod = 'title',
-- }
-- mw.logObject(a)
-- local q = dpl.ask{
-- uses = "Template:Collections table",
-- category = "Archaeology collections",
-- -- include = "{Infobox collection}:reward,{Collections table}:1:2:3:4:5:6:7:8:9:10:11:12:13:14:15",
-- include = "{Infobox collection}:reward,{Collections table}",
-- count = 100
-- }
-- mw.logObject(q)
-- local q = dpl.ask{
-- namespace = "",
-- uses = "Template:Infobox spell",
-- notcategory = {"Removed content", "Removed spells"},
-- nottitlematch = {"Enchant Crossbow Bolt", "Storm of Armadyl"},
-- include = "{Infobox spell}",
-- }
-- mw.logObject(q)
-- local list = dpl.ask{
-- namespace = 'Template',
-- uses = 'Template:Navbox',
-- ordermethod = 'title',
-- include = '{Navbox}:gtitle1:gtitle2',
-- count = 1,
-- offset = 3
-- }
-- mw.logObject(list)
-- local list = dpl.ask{
-- namespace = 'User',
-- titlematch = 'CephHunter/Sandbox/test1',
-- include = '{User:CephHunter/Sandbox/test2|User:CephHunter/Sandbox/test3},{User:CephHunter/Sandbox/test3}:1',
-- }
-- mw.logObject(list)
-- mw.logObject(dpl.ask{
-- namespace = 'User',
-- ignorecase = 'true',
-- titlematch = 'CephHunter/Sandbox/test1',
-- include = '{User:CephHunter/Sandbox/test2}'
-- })
-- mw.logObject(dpl.ask{
-- namespace = 'Module',
-- uses = 'Template:Helper module',
-- titlematch = '%/doc',
-- nottitlematch = 'Exchange/%|Exchange historical/%|Sandbox/%',
-- ordermethod = 'title',
-- include = '{Helper module}, {Helper module}:example',
-- count = 1,
-- offset = 13
-- })
-- mw.logObject(dpl.ask{
-- namespace = 'Module',
-- titlematch = 'Chart data|Absorbative calculator',
-- nottitlematch = 'Exchange/%|Exchange historical/%|Sandbox/%|%/doc|DPLlua%',
-- ordermethod = 'title',
-- include = '%0'
-- })
-- mw.logObject(dpl.ask{
-- uses = 'Template:Collections table',
-- include = '{Collections table}',
-- count = 5
-- })
-- mw.log(os.clock()-time)
-- end
return dpl
-- </nowiki>
a4585a9ed619b57adfaa5cf8d9279da529e74df5
Category:Templates using TemplateStyles
14
34
66
2021-05-09T07:08:56Z
Star>Alistair3149
0
wikitext
text/x-wiki
{{Category header|templates|using [[Star Citizen:TemplateStyles|TemplateStyles]]}}
[[Category:Templates]]
7281aa1e395de9d8c368a3975548ace744177ec3
Category:Graph, chart, and plot templates
14
13
24
2021-05-21T12:05:38Z
Star>Facerafter
0
1 revision imported
wikitext
text/x-wiki
{{Category header|templates|used to produce graphs}}
[[Category:Templates]]
d2eb48d7551d51c120fdbfa06a3981e0053afb31
Category:Main page templates
14
21
40
2021-05-21T12:05:38Z
Star>Facerafter
0
1 revision imported
wikitext
text/x-wiki
{{Category header|templates|used on the main page}}
[[Category:Templates]]
fe5a1f6fb0db7ec3bd95014a7935715fb7558c94
Category:Navplates
14
25
48
2021-05-21T20:58:04Z
Star>Facerafter
0
wikitext
text/x-wiki
'''Navplates''' are navigation components that help visitor to visit pages that fall under the same category.
[[Category:Templates]]
ffa7595179dc81205203c976231a54a062e09851
Category:External link templates
14
9
16
2022-05-04T18:29:23Z
Star>Alistair3149
0
Created page with "[[Category:Templates]]"
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Template:Category header
10
46
90
2022-05-10T07:07:39Z
Star>Alistair3149
0
Wrap in note template
wikitext
text/x-wiki
<includeonly>{{Note|This category contains {{{1}}}{{#if:{{{2|}}}|{{#ifeq:{{lc:{{{related|}}}}}|no||{{nbsp}}related to}}{{nbsp}}{{{2}}}}}. {{#if:{{{3|}}}|This category is automatically added by {{{4|}}}.}}}}</includeonly><noinclude>{{/doc}}</noinclude>
a396b20e4e0c621cc7538e9a0f085cfbbd37a811
Template:Day
10
2
2
2022-10-13T21:23:08Z
Star>Alistair3149
0
Short description already set in day header
wikitext
text/x-wiki
<includeonly>'''{{{1|{{FULLPAGENAME}}}}}''' is the {{#switch:{{#time:z|{{{1|{{PAGENAME}}}}}}}
|0=first
|1=second
|2=third
|3=fourth
|4=fifth
|5=sixth
|6=seventh
|7=eighth
|8=ninth
|{{ordinal|{{#expr:{{#time:z|{{{1|{{PAGENAME}}}}}, 2001}}+1}}}}
}} day of the year{{#ifexpr:{{#time:n|{{{1|{{PAGENAME}}}}}}}<3
|
| ({{ordinal|{{#expr:{{#time:z|{{{1|{{PAGENAME}}}}}, 2000}}+1}}}} in leap years)
}} in the Gregorian calendar.{{#switch:{{#expr:364-{{#time:z|{{{1|{{PAGENAME}}}}}, 2001}}}}
|0=
|1= One day remains until the end of the year.
|2= Two days remain until the end of the year.
|3= Three days remain until the end of the year.
|4= Four days remain until the end of the year.
|5= Five days remain until the end of the year.
|6= Six days remain until the end of the year.
|7= Seven days remain until the end of the year.
|8= Eight days remain until the end of the year.
|9= Nine days remain until the end of the year.
|  {{#expr:364-{{#time:z|{{{1|{{PAGENAME}}}}}, 2001}}}} days remain until the end of the year{{#ifexpr:{{#time:n|{{{1|{{PAGENAME}}}}}}}<3
| ({{#expr:365-{{#time:z|{{{1|{{PAGENAME}}}}}, 2000}}}} in leap years)
|
}}.
}}</includeonly><noinclude>{{/doc}}</noinclude>
530dc54fd9473a69e2d1ff775d7d2b2a6c206768
Module:Hatnote list
828
50
98
2023-01-23T23:06:33Z
star>Alistair3149
0
Scribunto
text/plain
--------------------------------------------------------------------------------
-- Module:Hatnote list --
-- --
-- This module produces and formats lists for use in hatnotes. In particular, --
-- it implements the for-see list, i.e. lists of "For X, see Y" statements, --
-- as used in {{about}}, {{redirect}}, and their variants. Also introduced --
-- are andList & orList helpers for formatting lists with those conjunctions. --
--------------------------------------------------------------------------------
local mArguments --initialize lazily
local mFormatLink = require('Module:Format link')
local mHatnote = require('Module:Hatnote')
local libraryUtil = require('libraryUtil')
local checkType = libraryUtil.checkType
local p = {}
--------------------------------------------------------------------------------
-- List stringification helper functions
--
-- These functions are used for stringifying lists, usually page lists inside
-- the "Y" portion of "For X, see Y" for-see items.
--------------------------------------------------------------------------------
--default options table used across the list stringification functions
local stringifyListDefaultOptions = {
conjunction = "and",
separator = ",",
altSeparator = ";",
space = " ",
formatted = false
}
--Searches display text only
local function searchDisp(haystack, needle)
return string.find(
string.sub(haystack, (string.find(haystack, '|') or 0) + 1), needle
)
end
-- Stringifies a list generically; probably shouldn't be used directly
local function stringifyList(list, options)
-- Type-checks, defaults, and a shortcut
checkType("stringifyList", 1, list, "table")
if #list == 0 then return nil end
checkType("stringifyList", 2, options, "table", true)
options = options or {}
for k, v in pairs(stringifyListDefaultOptions) do
if options[k] == nil then options[k] = v end
end
local s = options.space
-- Format the list if requested
if options.formatted then
list = mFormatLink.formatPages(
{categorizeMissing = mHatnote.missingTargetCat}, list
)
end
-- Set the separator; if any item contains it, use the alternate separator
local separator = options.separator
for k, v in pairs(list) do
if searchDisp(v, separator) then
separator = options.altSeparator
break
end
end
-- Set the conjunction, apply Oxford comma, and force a comma if #1 has "§"
local conjunction = s .. options.conjunction .. s
if #list == 2 and searchDisp(list[1], "§") or #list > 2 then
conjunction = separator .. conjunction
end
-- Return the formatted string
return mw.text.listToText(list, separator .. s, conjunction)
end
--DRY function
function p.conjList (conj, list, fmt)
return stringifyList(list, {conjunction = conj, formatted = fmt})
end
-- Stringifies lists with "and" or "or"
function p.andList (...) return p.conjList("and", ...) end
function p.orList (...) return p.conjList("or", ...) end
--------------------------------------------------------------------------------
-- For see
--
-- Makes a "For X, see [[Y]]." list from raw parameters. Intended for the
-- {{about}} and {{redirect}} templates and their variants.
--------------------------------------------------------------------------------
--default options table used across the forSee family of functions
local forSeeDefaultOptions = {
andKeyword = 'and',
title = mw.title.getCurrentTitle().text,
otherText = 'other uses',
forSeeForm = 'For %s, see %s.',
}
--Collapses duplicate punctuation
local function punctuationCollapse (text)
local replacements = {
["%.%.$"] = ".",
["%?%.$"] = "?",
["%!%.$"] = "!",
["%.%]%]%.$"] = ".]]",
["%?%]%]%.$"] = "?]]",
["%!%]%]%.$"] = "!]]"
}
for k, v in pairs(replacements) do text = string.gsub(text, k, v) end
return text
end
-- Structures arguments into a table for stringification, & options
function p.forSeeArgsToTable (args, from, options)
-- Type-checks and defaults
checkType("forSeeArgsToTable", 1, args, 'table')
checkType("forSeeArgsToTable", 2, from, 'number', true)
from = from or 1
checkType("forSeeArgsToTable", 3, options, 'table', true)
options = options or {}
for k, v in pairs(forSeeDefaultOptions) do
if options[k] == nil then options[k] = v end
end
-- maxArg's gotten manually because getArgs() and table.maxn aren't friends
local maxArg = 0
for k, v in pairs(args) do
if type(k) == 'number' and k > maxArg then maxArg = k end
end
-- Structure the data out from the parameter list:
-- * forTable is the wrapper table, with forRow rows
-- * Rows are tables of a "use" string & a "pages" table of pagename strings
-- * Blanks are left empty for defaulting elsewhere, but can terminate list
local forTable = {}
local i = from
local terminated = false
-- If there is extra text, and no arguments are given, give nil value
-- to not produce default of "For other uses, see foo (disambiguation)"
if options.extratext and i > maxArg then return nil end
-- Loop to generate rows
repeat
-- New empty row
local forRow = {}
-- On blank use, assume list's ended & break at end of this loop
forRow.use = args[i]
if not args[i] then terminated = true end
-- New empty list of pages
forRow.pages = {}
-- Insert first pages item if present
table.insert(forRow.pages, args[i + 1])
-- If the param after next is "and", do inner loop to collect params
-- until the "and"'s stop. Blanks are ignored: "1|and||and|3" → {1, 3}
while args[i + 2] == options.andKeyword do
if args[i + 3] then
table.insert(forRow.pages, args[i + 3])
end
-- Increment to next "and"
i = i + 2
end
-- Increment to next use
i = i + 2
-- Append the row
table.insert(forTable, forRow)
until terminated or i > maxArg
return forTable
end
-- Stringifies a table as formatted by forSeeArgsToTable
function p.forSeeTableToString (forSeeTable, options)
-- Type-checks and defaults
checkType("forSeeTableToString", 1, forSeeTable, "table", true)
checkType("forSeeTableToString", 2, options, "table", true)
options = options or {}
for k, v in pairs(forSeeDefaultOptions) do
if options[k] == nil then options[k] = v end
end
-- Stringify each for-see item into a list
local strList = {}
if forSeeTable then
for k, v in pairs(forSeeTable) do
local useStr = v.use or options.otherText
local pagesStr =
p.andList(v.pages, true) or
mFormatLink._formatLink{
categorizeMissing = mHatnote.missingTargetCat,
link = mHatnote.disambiguate(options.title)
}
local forSeeStr = string.format(options.forSeeForm, useStr, pagesStr)
forSeeStr = punctuationCollapse(forSeeStr)
table.insert(strList, forSeeStr)
end
end
if options.extratext then table.insert(strList, punctuationCollapse(options.extratext..'.')) end
-- Return the concatenated list
return table.concat(strList, ' ')
end
-- Produces a "For X, see [[Y]]" string from arguments. Expects index gaps
-- but not blank/whitespace values. Ignores named args and args < "from".
function p._forSee (args, from, options)
local forSeeTable = p.forSeeArgsToTable(args, from, options)
return p.forSeeTableToString(forSeeTable, options)
end
-- As _forSee, but uses the frame.
function p.forSee (frame, from, options)
mArguments = require('Module:Arguments')
return p._forSee(mArguments.getArgs(frame), from, options)
end
return p
d0828422b1aa0d0d0092d699d059c9e882260398
Module:Hatnote/styles.css
828
47
92
2023-01-24T01:51:43Z
Star>Alistair3149
0
text
text/plain
.hatnote-container {
display: flex;
align-items: center;
padding: var( --space-sm ) var( --space-md );
margin-top: var( --space-xs );
margin-bottom: var( --space-md );
background: var( --color-surface-2 );
border-radius: var( --border-radius--medium );
color: var( --color-base--subtle );
font-size: 0.875rem;
line-height: var( --line-height-xs );
}
.hatnote-icon img {
width: 14px;
height: auto;
margin-right: var( --space-xs );
opacity: var( --opacity-icon-base );
}
/* Dark theme */
html.skin-citizen-dark .hatnote-icon img {
filter: invert( 1 );
}
44850b74680c356f2514e4292d2130fb67f3b46d
Module:Arguments
828
40
78
2023-01-24T03:54:04Z
Star>Alistair3149
0
Protected "[[Module:Arguments]]" ([Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite))
Scribunto
text/plain
-- This module provides easy processing of arguments passed to Scribunto from
-- #invoke. It is intended for use by other Lua modules, and should not be
-- called from #invoke directly.
local libraryUtil = require('libraryUtil')
local checkType = libraryUtil.checkType
local arguments = {}
-- Generate four different tidyVal functions, so that we don't have to check the
-- options every time we call it.
local function tidyValDefault(key, val)
if type(val) == 'string' then
val = val:match('^%s*(.-)%s*$')
if val == '' then
return nil
else
return val
end
else
return val
end
end
local function tidyValTrimOnly(key, val)
if type(val) == 'string' then
return val:match('^%s*(.-)%s*$')
else
return val
end
end
local function tidyValRemoveBlanksOnly(key, val)
if type(val) == 'string' then
if val:find('%S') then
return val
else
return nil
end
else
return val
end
end
local function tidyValNoChange(key, val)
return val
end
local function matchesTitle(given, title)
local tp = type( given )
return (tp == 'string' or tp == 'number') and mw.title.new( given ).prefixedText == title
end
local translate_mt = { __index = function(t, k) return k end }
function arguments.getArgs(frame, options)
checkType('getArgs', 1, frame, 'table', true)
checkType('getArgs', 2, options, 'table', true)
frame = frame or {}
options = options or {}
--[[
-- Set up argument translation.
--]]
options.translate = options.translate or {}
if getmetatable(options.translate) == nil then
setmetatable(options.translate, translate_mt)
end
if options.backtranslate == nil then
options.backtranslate = {}
for k,v in pairs(options.translate) do
options.backtranslate[v] = k
end
end
if options.backtranslate and getmetatable(options.backtranslate) == nil then
setmetatable(options.backtranslate, {
__index = function(t, k)
if options.translate[k] ~= k then
return nil
else
return k
end
end
})
end
--[[
-- Get the argument tables. If we were passed a valid frame object, get the
-- frame arguments (fargs) and the parent frame arguments (pargs), depending
-- on the options set and on the parent frame's availability. If we weren't
-- passed a valid frame object, we are being called from another Lua module
-- or from the debug console, so assume that we were passed a table of args
-- directly, and assign it to a new variable (luaArgs).
--]]
local fargs, pargs, luaArgs
if type(frame.args) == 'table' and type(frame.getParent) == 'function' then
if options.wrappers then
--[[
-- The wrappers option makes Module:Arguments look up arguments in
-- either the frame argument table or the parent argument table, but
-- not both. This means that users can use either the #invoke syntax
-- or a wrapper template without the loss of performance associated
-- with looking arguments up in both the frame and the parent frame.
-- Module:Arguments will look up arguments in the parent frame
-- if it finds the parent frame's title in options.wrapper;
-- otherwise it will look up arguments in the frame object passed
-- to getArgs.
--]]
local parent = frame:getParent()
if not parent then
fargs = frame.args
else
local title = parent:getTitle():gsub('/sandbox$', '')
local found = false
if matchesTitle(options.wrappers, title) then
found = true
elseif type(options.wrappers) == 'table' then
for _,v in pairs(options.wrappers) do
if matchesTitle(v, title) then
found = true
break
end
end
end
-- We test for false specifically here so that nil (the default) acts like true.
if found or options.frameOnly == false then
pargs = parent.args
end
if not found or options.parentOnly == false then
fargs = frame.args
end
end
else
-- options.wrapper isn't set, so check the other options.
if not options.parentOnly then
fargs = frame.args
end
if not options.frameOnly then
local parent = frame:getParent()
pargs = parent and parent.args or nil
end
end
if options.parentFirst then
fargs, pargs = pargs, fargs
end
else
luaArgs = frame
end
-- Set the order of precedence of the argument tables. If the variables are
-- nil, nothing will be added to the table, which is how we avoid clashes
-- between the frame/parent args and the Lua args.
local argTables = {fargs}
argTables[#argTables + 1] = pargs
argTables[#argTables + 1] = luaArgs
--[[
-- Generate the tidyVal function. If it has been specified by the user, we
-- use that; if not, we choose one of four functions depending on the
-- options chosen. This is so that we don't have to call the options table
-- every time the function is called.
--]]
local tidyVal = options.valueFunc
if tidyVal then
if type(tidyVal) ~= 'function' then
error(
"bad value assigned to option 'valueFunc'"
.. '(function expected, got '
.. type(tidyVal)
.. ')',
2
)
end
elseif options.trim ~= false then
if options.removeBlanks ~= false then
tidyVal = tidyValDefault
else
tidyVal = tidyValTrimOnly
end
else
if options.removeBlanks ~= false then
tidyVal = tidyValRemoveBlanksOnly
else
tidyVal = tidyValNoChange
end
end
--[[
-- Set up the args, metaArgs and nilArgs tables. args will be the one
-- accessed from functions, and metaArgs will hold the actual arguments. Nil
-- arguments are memoized in nilArgs, and the metatable connects all of them
-- together.
--]]
local args, metaArgs, nilArgs, metatable = {}, {}, {}, {}
setmetatable(args, metatable)
local function mergeArgs(tables)
--[[
-- Accepts multiple tables as input and merges their keys and values
-- into one table. If a value is already present it is not overwritten;
-- tables listed earlier have precedence. We are also memoizing nil
-- values, which can be overwritten if they are 's' (soft).
--]]
for _, t in ipairs(tables) do
for key, val in pairs(t) do
if metaArgs[key] == nil and nilArgs[key] ~= 'h' then
local tidiedVal = tidyVal(key, val)
if tidiedVal == nil then
nilArgs[key] = 's'
else
metaArgs[key] = tidiedVal
end
end
end
end
end
--[[
-- Define metatable behaviour. Arguments are memoized in the metaArgs table,
-- and are only fetched from the argument tables once. Fetching arguments
-- from the argument tables is the most resource-intensive step in this
-- module, so we try and avoid it where possible. For this reason, nil
-- arguments are also memoized, in the nilArgs table. Also, we keep a record
-- in the metatable of when pairs and ipairs have been called, so we do not
-- run pairs and ipairs on the argument tables more than once. We also do
-- not run ipairs on fargs and pargs if pairs has already been run, as all
-- the arguments will already have been copied over.
--]]
metatable.__index = function (t, key)
--[[
-- Fetches an argument when the args table is indexed. First we check
-- to see if the value is memoized, and if not we try and fetch it from
-- the argument tables. When we check memoization, we need to check
-- metaArgs before nilArgs, as both can be non-nil at the same time.
-- If the argument is not present in metaArgs, we also check whether
-- pairs has been run yet. If pairs has already been run, we return nil.
-- This is because all the arguments will have already been copied into
-- metaArgs by the mergeArgs function, meaning that any other arguments
-- must be nil.
--]]
if type(key) == 'string' then
key = options.translate[key]
end
local val = metaArgs[key]
if val ~= nil then
return val
elseif metatable.donePairs or nilArgs[key] then
return nil
end
for _, argTable in ipairs(argTables) do
local argTableVal = tidyVal(key, argTable[key])
if argTableVal ~= nil then
metaArgs[key] = argTableVal
return argTableVal
end
end
nilArgs[key] = 'h'
return nil
end
metatable.__newindex = function (t, key, val)
-- This function is called when a module tries to add a new value to the
-- args table, or tries to change an existing value.
if type(key) == 'string' then
key = options.translate[key]
end
if options.readOnly then
error(
'could not write to argument table key "'
.. tostring(key)
.. '"; the table is read-only',
2
)
elseif options.noOverwrite and args[key] ~= nil then
error(
'could not write to argument table key "'
.. tostring(key)
.. '"; overwriting existing arguments is not permitted',
2
)
elseif val == nil then
--[[
-- If the argument is to be overwritten with nil, we need to erase
-- the value in metaArgs, so that __index, __pairs and __ipairs do
-- not use a previous existing value, if present; and we also need
-- to memoize the nil in nilArgs, so that the value isn't looked
-- up in the argument tables if it is accessed again.
--]]
metaArgs[key] = nil
nilArgs[key] = 'h'
else
metaArgs[key] = val
end
end
local function translatenext(invariant)
local k, v = next(invariant.t, invariant.k)
invariant.k = k
if k == nil then
return nil
elseif type(k) ~= 'string' or not options.backtranslate then
return k, v
else
local backtranslate = options.backtranslate[k]
if backtranslate == nil then
-- Skip this one. This is a tail call, so this won't cause stack overflow
return translatenext(invariant)
else
return backtranslate, v
end
end
end
metatable.__pairs = function ()
-- Called when pairs is run on the args table.
if not metatable.donePairs then
mergeArgs(argTables)
metatable.donePairs = true
end
return translatenext, { t = metaArgs }
end
local function inext(t, i)
-- This uses our __index metamethod
local v = t[i + 1]
if v ~= nil then
return i + 1, v
end
end
metatable.__ipairs = function (t)
-- Called when ipairs is run on the args table.
return inext, t, 0
end
return args
end
return arguments
3134ecce8429b810d445e29eae115e2ae4c36c53
Template:Note
10
42
82
2023-01-24T21:45:35Z
Star>Alistair3149
0
Alistair3149 moved page [[Template:Note]] to [[Template:Hatnote]]
wikitext
text/x-wiki
#REDIRECT [[Template:Hatnote]]
9582e82fbead373024765d896e4930eee521d846
Template:Hatnote
10
48
94
2023-01-24T21:45:35Z
Star>Alistair3149
0
Alistair3149 moved page [[Template:Note]] to [[Template:Hatnote]]
wikitext
text/x-wiki
<includeonly>{{#invoke:Hatnote|hatnote}}</includeonly><noinclude>{{/doc}}</noinclude>
d9029e1bc2de056708cda99e6ce883644c1661e4
Category:Preload text templates
14
28
54
2023-04-25T16:46:32Z
Star>Alistair3149
0
Created page with "{{Category header|templates|used for article creation}} [[Category:Templates]]"
wikitext
text/x-wiki
{{Category header|templates|used for article creation}}
[[Category:Templates]]
21360b4c5b0d6bef10209484084e8beb67641662
Module:Infobox
828
58
114
2023-05-29T18:00:43Z
star>Alistair3149
0
Load templatestyles through module instead
Scribunto
text/plain
--
-- This module implements {{Infobox}}
--
local p = {}
-- local navbar = require('Module:Navbar')._navbar
local args = {}
local origArgs
local root
local function notempty( s ) return s and s:match( '%S' ) end
local function fixChildBoxes(sval, tt)
if notempty(sval) then
local marker = '<span class=special_infobox_marker>'
local s = sval
s = mw.ustring.gsub(s, '(<%s*[Tt][Rr])', marker .. '%1')
s = mw.ustring.gsub(s, '(</[Tt][Rr]%s*>)', '%1' .. marker)
if s:match(marker) then
s = mw.ustring.gsub(s, marker .. '%s*' .. marker, '')
s = mw.ustring.gsub(s, '([\r\n]|-[^\r\n]*[\r\n])%s*' .. marker, '%1')
s = mw.ustring.gsub(s, marker .. '%s*([\r\n]|-)', '%1')
s = mw.ustring.gsub(s, '(</[Cc][Aa][Pp][Tt][Ii][Oo][Nn]%s*>%s*)' .. marker, '%1')
s = mw.ustring.gsub(s, '(<%s*[Tt][Aa][Bb][Ll][Ee][^<>]*>%s*)' .. marker, '%1')
s = mw.ustring.gsub(s, '^(%{|[^\r\n]*[\r\n]%s*)' .. marker, '%1')
s = mw.ustring.gsub(s, '([\r\n]%{|[^\r\n]*[\r\n]%s*)' .. marker, '%1')
s = mw.ustring.gsub(s, marker .. '(%s*</[Tt][Aa][Bb][Ll][Ee]%s*>)', '%1')
s = mw.ustring.gsub(s, marker .. '(%s*\n|%})', '%1')
end
if s:match(marker) then
local subcells = mw.text.split(s, marker)
s = ''
for k = 1, #subcells do
if k == 1 then
s = s .. subcells[k] .. '</' .. tt .. '></tr>'
elseif k == #subcells then
local rowstyle = ' style="display:none"'
if notempty(subcells[k]) then rowstyle = '' end
s = s .. '<tr' .. rowstyle ..'><' .. tt .. ' colspan=2>\n' .. subcells[k]
elseif notempty(subcells[k]) then
if (k % 2) == 0 then
s = s .. subcells[k]
else
s = s .. '<tr><' .. tt .. ' colspan=2>\n' .. subcells[k] .. '</' .. tt .. '></tr>'
end
end
end
end
-- the next two lines add a newline at the end of lists for the PHP parser
-- https://en.wikipedia.org/w/index.php?title=Template_talk:Infobox_musical_artist&oldid=849054481
-- remove when [[:phab:T191516]] is fixed or OBE
s = mw.ustring.gsub(s, '([\r\n][%*#;:][^\r\n]*)$', '%1\n')
s = mw.ustring.gsub(s, '^([%*#;:][^\r\n]*)$', '%1\n')
s = mw.ustring.gsub(s, '^([%*#;:])', '\n%1')
s = mw.ustring.gsub(s, '^(%{%|)', '\n%1')
return s
else
return sval
end
end
local function union(t1, t2)
-- Returns the union of the values of two tables, as a sequence.
local vals = {}
for k, v in pairs(t1) do
vals[v] = true
end
for k, v in pairs(t2) do
vals[v] = true
end
local ret = {}
for k, v in pairs(vals) do
table.insert(ret, k)
end
return ret
end
local function getArgNums(prefix)
-- Returns a table containing the numbers of the arguments that exist
-- for the specified prefix. For example, if the prefix was 'data', and
-- 'data1', 'data2', and 'data5' exist, it would return {1, 2, 5}.
local nums = {}
for k, v in pairs(args) do
local num = tostring(k):match('^' .. prefix .. '([1-9]%d*)$')
if num then table.insert(nums, tonumber(num)) end
end
table.sort(nums)
return nums
end
local function addRow(rowArgs)
-- Adds a row to the infobox, with either a header cell
-- or a label/data cell combination.
if rowArgs.header then
root
:tag('tr')
:addClass(rowArgs.rowclass)
:cssText(rowArgs.rowstyle)
:attr('id', rowArgs.rowid)
:tag('th')
:attr('colspan', 2)
:attr('id', rowArgs.headerid)
:addClass(rowArgs.class)
:addClass(args.headerclass)
----:css('text-align', 'center')
:cssText(args.headerstyle)
:cssText(rowArgs.rowcellstyle)
:wikitext(fixChildBoxes(rowArgs.header, 'th'))
elseif rowArgs.data then
local row = root:tag('tr')
row:addClass(rowArgs.rowclass)
row:cssText(rowArgs.rowstyle)
row:attr('id', rowArgs.rowid)
if rowArgs.label then
row
:tag('th')
:attr('scope', 'row')
:attr('id', rowArgs.labelid)
:cssText(args.labelstyle)
:cssText(rowArgs.rowcellstyle)
:wikitext(rowArgs.label)
:done()
end
local dataCell = row:tag('td')
if not rowArgs.label then
dataCell
:attr('colspan', 2)
----:css('text-align', 'center')
end
dataCell
:attr('id', rowArgs.dataid)
:addClass(rowArgs.class)
:cssText(rowArgs.datastyle)
:cssText(rowArgs.rowcellstyle)
:wikitext(fixChildBoxes(rowArgs.data, 'td'))
end
end
local function renderTitle()
if not args.title then return end
root
:tag('caption')
:addClass(args.titleclass)
:cssText(args.titlestyle)
:wikitext(args.title)
end
local function renderAboveRow()
if not args.above then return end
root
:tag('tr')
:tag('th')
:attr('colspan', 2)
:addClass(args.aboveclass)
--:css('text-align', 'center')
--:css('font-size', '125%')
--:css('font-weight', 'bold')
:cssText(args.abovestyle)
:wikitext(fixChildBoxes(args.above,'th'))
end
local function renderBelowRow()
if not args.below then return end
root
:tag('tr')
:tag('td')
:attr('colspan', '2')
:addClass(args.belowclass)
--:css('text-align', 'center')
:cssText(args.belowstyle)
:wikitext(fixChildBoxes(args.below,'td'))
end
local function renderSubheaders()
if args.subheader then
args.subheader1 = args.subheader
end
if args.subheaderrowclass then
args.subheaderrowclass1 = args.subheaderrowclass
end
local subheadernums = getArgNums('subheader')
for k, num in ipairs(subheadernums) do
addRow({
data = args['subheader' .. tostring(num)],
datastyle = args.subheaderstyle,
rowcellstyle = args['subheaderstyle' .. tostring(num)],
class = args.subheaderclass,
rowclass = args['subheaderrowclass' .. tostring(num)]
})
end
end
local function renderImages()
if args.image then
args.image1 = args.image
end
if args.caption then
args.caption1 = args.caption
end
local imagenums = getArgNums('image')
for k, num in ipairs(imagenums) do
local caption = args['caption' .. tostring(num)]
local data = mw.html.create():wikitext(args['image' .. tostring(num)])
if caption then
data
:tag('div')
:cssText(args.captionstyle)
:wikitext(caption)
end
addRow({
data = tostring(data),
datastyle = args.imagestyle,
class = args.imageclass,
rowclass = args['imagerowclass' .. tostring(num)]
})
end
end
local function renderRows()
-- Gets the union of the header and data argument numbers,
-- and renders them all in order using addRow.
local rownums = union(getArgNums('header'), getArgNums('data'))
table.sort(rownums)
for k, num in ipairs(rownums) do
addRow({
header = args['header' .. tostring(num)],
label = args['label' .. tostring(num)],
data = args['data' .. tostring(num)],
datastyle = args.datastyle,
class = args['class' .. tostring(num)],
rowclass = args['rowclass' .. tostring(num)],
rowstyle = args['rowstyle' .. tostring(num)],
rowcellstyle = args['rowcellstyle' .. tostring(num)],
dataid = args['dataid' .. tostring(num)],
labelid = args['labelid' .. tostring(num)],
headerid = args['headerid' .. tostring(num)],
rowid = args['rowid' .. tostring(num)]
})
end
end
--local function renderNavBar()
-- if not args.name then return end
--
-- root
-- :tag('tr')
-- :tag('td')
-- :attr('colspan', '2')
-- --:css('text-align', 'right')
-- :wikitext(navbar{
-- args.name,
-- mini = 1,
-- })
--end
local function renderItalicTitle()
local italicTitle = args['italic title'] and mw.ustring.lower(args['italic title'])
if italicTitle == '' or italicTitle == 'force' or italicTitle == 'yes' then
root:wikitext(mw.getCurrentFrame():expandTemplate({title = 'italic title'}))
end
end
local function renderTrackingCategories()
if args.decat ~= 'yes' then
if args.child == 'yes' then
if args.title then
root:wikitext('[[Category:Pages which use embedded infobox templates with the title parameter]]')
end
elseif #(getArgNums('data')) == 0 and mw.title.getCurrentTitle().namespace == 0 then
root:wikitext('[[Category:Articles which use infobox templates with no data rows]]')
end
end
end
local function _infobox()
-- Specify the overall layout of the infobox, with special settings
-- if the infobox is used as a 'child' inside another infobox.
if args.child ~= 'yes' then
root = mw.html.create('table')
root
:addClass((args.subbox ~= 'yes') and 'infobox' or nil)
:addClass(args.bodyclass)
--if args.subbox == 'yes' then
--root
--:css('padding', '0')
--:css('border', 'none')
--:css('margin', '-3px')
--:css('width', 'auto')
--:css('min-width', '100%')
--:css('font-size', '100%')
--:css('clear', 'none')
--:css('float', 'none')
--:css('background-color', 'transparent')
--else
--root
--:css('width', '400px') -- Changed from 22em
--end
root
:cssText(args.bodystyle)
renderTitle()
renderAboveRow()
else
root = mw.html.create()
root
:wikitext(args.title)
end
renderSubheaders()
renderImages()
renderRows()
renderBelowRow()
--renderNavBar()
renderItalicTitle()
renderTrackingCategories()
return tostring(root) .. mw.getCurrentFrame():extensionTag{
name = 'templatestyles', args = { src = 'Module:Infobox/styles.css' }
}
end
local function preprocessSingleArg(argName)
-- If the argument exists and isn't blank, add it to the argument table.
-- Blank arguments are treated as nil to match the behaviour of ParserFunctions.
if origArgs[argName] and origArgs[argName] ~= '' then
args[argName] = origArgs[argName]
end
end
local function preprocessArgs(prefixTable, step)
-- Assign the parameters with the given prefixes to the args table, in order, in batches
-- of the step size specified. This is to prevent references etc. from appearing in the
-- wrong order. The prefixTable should be an array containing tables, each of which has
-- two possible fields, a "prefix" string and a "depend" table. The function always parses
-- parameters containing the "prefix" string, but only parses parameters in the "depend"
-- table if the prefix parameter is present and non-blank.
if type(prefixTable) ~= 'table' then
error("Non-table value detected for the prefix table", 2)
end
if type(step) ~= 'number' then
error("Invalid step value detected", 2)
end
-- Get arguments without a number suffix, and check for bad input.
for i,v in ipairs(prefixTable) do
if type(v) ~= 'table' or type(v.prefix) ~= "string" or (v.depend and type(v.depend) ~= 'table') then
error('Invalid input detected to preprocessArgs prefix table', 2)
end
preprocessSingleArg(v.prefix)
-- Only parse the depend parameter if the prefix parameter is present and not blank.
if args[v.prefix] and v.depend then
for j, dependValue in ipairs(v.depend) do
if type(dependValue) ~= 'string' then
error('Invalid "depend" parameter value detected in preprocessArgs')
end
preprocessSingleArg(dependValue)
end
end
end
-- Get arguments with number suffixes.
local a = 1 -- Counter variable.
local moreArgumentsExist = true
while moreArgumentsExist == true do
moreArgumentsExist = false
for i = a, a + step - 1 do
for j,v in ipairs(prefixTable) do
local prefixArgName = v.prefix .. tostring(i)
if origArgs[prefixArgName] then
moreArgumentsExist = true -- Do another loop if any arguments are found, even blank ones.
preprocessSingleArg(prefixArgName)
end
-- Process the depend table if the prefix argument is present and not blank, or
-- we are processing "prefix1" and "prefix" is present and not blank, and
-- if the depend table is present.
if v.depend and (args[prefixArgName] or (i == 1 and args[v.prefix])) then
for j,dependValue in ipairs(v.depend) do
local dependArgName = dependValue .. tostring(i)
preprocessSingleArg(dependArgName)
end
end
end
end
a = a + step
end
end
function p.infobox(frame)
-- If called via #invoke, use the args passed into the invoking template.
-- Otherwise, for testing purposes, assume args are being passed directly in.
if frame == mw.getCurrentFrame() then
origArgs = frame:getParent().args
else
origArgs = frame
end
-- Parse the data parameters in the same order that the old {{infobox}} did, so that
-- references etc. will display in the expected places. Parameters that depend on
-- another parameter are only processed if that parameter is present, to avoid
-- phantom references appearing in article reference lists.
preprocessSingleArg('child')
preprocessSingleArg('bodyclass')
preprocessSingleArg('subbox')
preprocessSingleArg('bodystyle')
preprocessSingleArg('title')
preprocessSingleArg('titleclass')
preprocessSingleArg('titlestyle')
preprocessSingleArg('above')
preprocessSingleArg('aboveclass')
preprocessSingleArg('abovestyle')
preprocessArgs({
{prefix = 'subheader', depend = {'subheaderstyle', 'subheaderrowclass'}}
}, 10)
preprocessSingleArg('subheaderstyle')
preprocessSingleArg('subheaderclass')
preprocessArgs({
{prefix = 'image', depend = {'caption', 'imagerowclass'}}
}, 10)
preprocessSingleArg('captionstyle')
preprocessSingleArg('imagestyle')
preprocessSingleArg('imageclass')
preprocessArgs({
{prefix = 'header'},
{prefix = 'data', depend = {'label'}},
{prefix = 'rowclass'},
{prefix = 'rowstyle'},
{prefix = 'rowcellstyle'},
{prefix = 'class'},
{prefix = 'dataid'},
{prefix = 'labelid'},
{prefix = 'headerid'},
{prefix = 'rowid'}
}, 50)
preprocessSingleArg('headerclass')
preprocessSingleArg('headerstyle')
preprocessSingleArg('labelstyle')
preprocessSingleArg('datastyle')
preprocessSingleArg('below')
preprocessSingleArg('belowclass')
preprocessSingleArg('belowstyle')
preprocessSingleArg('name')
args['italic title'] = origArgs['italic title'] -- different behaviour if blank or absent
preprocessSingleArg('decat')
return _infobox()
end
return p
2e046db27a7f61675131debae5a131a9dee12195
Template:Infobox
10
49
96
2023-05-29T18:01:05Z
star>Alistair3149
0
Load templatestyles through module instead
wikitext
text/x-wiki
{{#invoke:Infobox|infobox}}<noinclude>
{{/doc}}
<!-- Categories go in the /doc subpage, and interwikis go in Wikidata. -->
</noinclude>
aaadab5f0433ae495a07ed115145bf7ca42d5c10
Module:String
828
43
84
2023-05-30T20:14:41Z
Star>Alistair3149
0
Sync with Wikipedia
Scribunto
text/plain
--[[
This module is intended to provide access to basic string functions.
Most of the functions provided here can be invoked with named parameters,
unnamed parameters, or a mixture. If named parameters are used, Mediawiki will
automatically remove any leading or trailing whitespace from the parameter.
Depending on the intended use, it may be advantageous to either preserve or
remove such whitespace.
Global options
ignore_errors: If set to 'true' or 1, any error condition will result in
an empty string being returned rather than an error message.
error_category: If an error occurs, specifies the name of a category to
include with the error message. The default category is
[Category:Errors reported by Module String].
no_category: If set to 'true' or 1, no category will be added if an error
is generated.
Unit tests for this module are available at Module:String/tests.
]]
local str = {}
--[[
len
This function returns the length of the target string.
Usage:
{{#invoke:String|len|target_string|}}
OR
{{#invoke:String|len|s=target_string}}
Parameters
s: The string whose length to report
If invoked using named parameters, Mediawiki will automatically remove any leading or
trailing whitespace from the target string.
]]
function str.len( frame )
local new_args = str._getParameters( frame.args, {'s'} )
local s = new_args['s'] or ''
return mw.ustring.len( s )
end
--[[
sub
This function returns a substring of the target string at specified indices.
Usage:
{{#invoke:String|sub|target_string|start_index|end_index}}
OR
{{#invoke:String|sub|s=target_string|i=start_index|j=end_index}}
Parameters
s: The string to return a subset of
i: The fist index of the substring to return, defaults to 1.
j: The last index of the string to return, defaults to the last character.
The first character of the string is assigned an index of 1. If either i or j
is a negative value, it is interpreted the same as selecting a character by
counting from the end of the string. Hence, a value of -1 is the same as
selecting the last character of the string.
If the requested indices are out of range for the given string, an error is
reported.
]]
function str.sub( frame )
local new_args = str._getParameters( frame.args, { 's', 'i', 'j' } )
local s = new_args['s'] or ''
local i = tonumber( new_args['i'] ) or 1
local j = tonumber( new_args['j'] ) or -1
local len = mw.ustring.len( s )
-- Convert negatives for range checking
if i < 0 then
i = len + i + 1
end
if j < 0 then
j = len + j + 1
end
if i > len or j > len or i < 1 or j < 1 then
return str._error( 'String subset index out of range' )
end
if j < i then
return str._error( 'String subset indices out of order' )
end
return mw.ustring.sub( s, i, j )
end
--[[
This function implements that features of {{str sub old}} and is kept in order
to maintain these older templates.
]]
function str.sublength( frame )
local i = tonumber( frame.args.i ) or 0
local len = tonumber( frame.args.len )
return mw.ustring.sub( frame.args.s, i + 1, len and ( i + len ) )
end
--[[
_match
This function returns a substring from the source string that matches a
specified pattern. It is exported for use in other modules
Usage:
strmatch = require("Module:String")._match
sresult = strmatch( s, pattern, start, match, plain, nomatch )
Parameters
s: The string to search
pattern: The pattern or string to find within the string
start: The index within the source string to start the search. The first
character of the string has index 1. Defaults to 1.
match: In some cases it may be possible to make multiple matches on a single
string. This specifies which match to return, where the first match is
match= 1. If a negative number is specified then a match is returned
counting from the last match. Hence match = -1 is the same as requesting
the last match. Defaults to 1.
plain: A flag indicating that the pattern should be understood as plain
text. Defaults to false.
nomatch: If no match is found, output the "nomatch" value rather than an error.
For information on constructing Lua patterns, a form of [regular expression], see:
* http://www.lua.org/manual/5.1/manual.html#5.4.1
* http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Patterns
* http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Ustring_patterns
]]
-- This sub-routine is exported for use in other modules
function str._match( s, pattern, start, match_index, plain_flag, nomatch )
if s == '' then
return str._error( 'Target string is empty' )
end
if pattern == '' then
return str._error( 'Pattern string is empty' )
end
start = tonumber(start) or 1
if math.abs(start) < 1 or math.abs(start) > mw.ustring.len( s ) then
return str._error( 'Requested start is out of range' )
end
if match_index == 0 then
return str._error( 'Match index is out of range' )
end
if plain_flag then
pattern = str._escapePattern( pattern )
end
local result
if match_index == 1 then
-- Find first match is simple case
result = mw.ustring.match( s, pattern, start )
else
if start > 1 then
s = mw.ustring.sub( s, start )
end
local iterator = mw.ustring.gmatch(s, pattern)
if match_index > 0 then
-- Forward search
for w in iterator do
match_index = match_index - 1
if match_index == 0 then
result = w
break
end
end
else
-- Reverse search
local result_table = {}
local count = 1
for w in iterator do
result_table[count] = w
count = count + 1
end
result = result_table[ count + match_index ]
end
end
if result == nil then
if nomatch == nil then
return str._error( 'Match not found' )
else
return nomatch
end
else
return result
end
end
--[[
match
This function returns a substring from the source string that matches a
specified pattern.
Usage:
{{#invoke:String|match|source_string|pattern_string|start_index|match_number|plain_flag|nomatch_output}}
OR
{{#invoke:String|match|s=source_string|pattern=pattern_string|start=start_index
|match=match_number|plain=plain_flag|nomatch=nomatch_output}}
Parameters
s: The string to search
pattern: The pattern or string to find within the string
start: The index within the source string to start the search. The first
character of the string has index 1. Defaults to 1.
match: In some cases it may be possible to make multiple matches on a single
string. This specifies which match to return, where the first match is
match= 1. If a negative number is specified then a match is returned
counting from the last match. Hence match = -1 is the same as requesting
the last match. Defaults to 1.
plain: A flag indicating that the pattern should be understood as plain
text. Defaults to false.
nomatch: If no match is found, output the "nomatch" value rather than an error.
If invoked using named parameters, Mediawiki will automatically remove any leading or
trailing whitespace from each string. In some circumstances this is desirable, in
other cases one may want to preserve the whitespace.
If the match_number or start_index are out of range for the string being queried, then
this function generates an error. An error is also generated if no match is found.
If one adds the parameter ignore_errors=true, then the error will be suppressed and
an empty string will be returned on any failure.
For information on constructing Lua patterns, a form of [regular expression], see:
* http://www.lua.org/manual/5.1/manual.html#5.4.1
* http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Patterns
* http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Ustring_patterns
]]
-- This is the entry point for #invoke:String|match
function str.match( frame )
local new_args = str._getParameters( frame.args, {'s', 'pattern', 'start', 'match', 'plain', 'nomatch'} )
local s = new_args['s'] or ''
local start = tonumber( new_args['start'] ) or 1
local plain_flag = str._getBoolean( new_args['plain'] or false )
local pattern = new_args['pattern'] or ''
local match_index = math.floor( tonumber(new_args['match']) or 1 )
local nomatch = new_args['nomatch']
return str._match( s, pattern, start, match_index, plain_flag, nomatch )
end
--[[
pos
This function returns a single character from the target string at position pos.
Usage:
{{#invoke:String|pos|target_string|index_value}}
OR
{{#invoke:String|pos|target=target_string|pos=index_value}}
Parameters
target: The string to search
pos: The index for the character to return
If invoked using named parameters, Mediawiki will automatically remove any leading or
trailing whitespace from the target string. In some circumstances this is desirable, in
other cases one may want to preserve the whitespace.
The first character has an index value of 1.
If one requests a negative value, this function will select a character by counting backwards
from the end of the string. In other words pos = -1 is the same as asking for the last character.
A requested value of zero, or a value greater than the length of the string returns an error.
]]
function str.pos( frame )
local new_args = str._getParameters( frame.args, {'target', 'pos'} )
local target_str = new_args['target'] or ''
local pos = tonumber( new_args['pos'] ) or 0
if pos == 0 or math.abs(pos) > mw.ustring.len( target_str ) then
return str._error( 'String index out of range' )
end
return mw.ustring.sub( target_str, pos, pos )
end
--[[
str_find
This function duplicates the behavior of {{str_find}}, including all of its quirks.
This is provided in order to support existing templates, but is NOT RECOMMENDED for
new code and templates. New code is recommended to use the "find" function instead.
Returns the first index in "source" that is a match to "target". Indexing is 1-based,
and the function returns -1 if the "target" string is not present in "source".
Important Note: If the "target" string is empty / missing, this function returns a
value of "1", which is generally unexpected behavior, and must be accounted for
separatetly.
]]
function str.str_find( frame )
local new_args = str._getParameters( frame.args, {'source', 'target'} )
local source_str = new_args['source'] or ''
local target_str = new_args['target'] or ''
if target_str == '' then
return 1
end
local start = mw.ustring.find( source_str, target_str, 1, true )
if start == nil then
start = -1
end
return start
end
--[[
find
This function allows one to search for a target string or pattern within another
string.
Usage:
{{#invoke:String|find|source_str|target_string|start_index|plain_flag}}
OR
{{#invoke:String|find|source=source_str|target=target_str|start=start_index|plain=plain_flag}}
Parameters
source: The string to search
target: The string or pattern to find within source
start: The index within the source string to start the search, defaults to 1
plain: Boolean flag indicating that target should be understood as plain
text and not as a Lua style regular expression, defaults to true
If invoked using named parameters, Mediawiki will automatically remove any leading or
trailing whitespace from the parameter. In some circumstances this is desirable, in
other cases one may want to preserve the whitespace.
This function returns the first index >= "start" where "target" can be found
within "source". Indices are 1-based. If "target" is not found, then this
function returns 0. If either "source" or "target" are missing / empty, this
function also returns 0.
This function should be safe for UTF-8 strings.
]]
function str.find( frame )
local new_args = str._getParameters( frame.args, {'source', 'target', 'start', 'plain' } )
local source_str = new_args['source'] or ''
local pattern = new_args['target'] or ''
local start_pos = tonumber(new_args['start']) or 1
local plain = new_args['plain'] or true
if source_str == '' or pattern == '' then
return 0
end
plain = str._getBoolean( plain )
local start = mw.ustring.find( source_str, pattern, start_pos, plain )
if start == nil then
start = 0
end
return start
end
--[[
replace
This function allows one to replace a target string or pattern within another
string.
Usage:
{{#invoke:String|replace|source_str|pattern_string|replace_string|replacement_count|plain_flag}}
OR
{{#invoke:String|replace|source=source_string|pattern=pattern_string|replace=replace_string|
count=replacement_count|plain=plain_flag}}
Parameters
source: The string to search
pattern: The string or pattern to find within source
replace: The replacement text
count: The number of occurences to replace, defaults to all.
plain: Boolean flag indicating that pattern should be understood as plain
text and not as a Lua style regular expression, defaults to true
]]
function str.replace( frame )
local new_args = str._getParameters( frame.args, {'source', 'pattern', 'replace', 'count', 'plain' } )
local source_str = new_args['source'] or ''
local pattern = new_args['pattern'] or ''
local replace = new_args['replace'] or ''
local count = tonumber( new_args['count'] )
local plain = new_args['plain'] or true
if source_str == '' or pattern == '' then
return source_str
end
plain = str._getBoolean( plain )
if plain then
pattern = str._escapePattern( pattern )
replace = mw.ustring.gsub( replace, "%%", "%%%%" ) --Only need to escape replacement sequences.
end
local result
if count ~= nil then
result = mw.ustring.gsub( source_str, pattern, replace, count )
else
result = mw.ustring.gsub( source_str, pattern, replace )
end
return result
end
--[[
simple function to pipe string.rep to templates.
]]
function str.rep( frame )
local repetitions = tonumber( frame.args[2] )
if not repetitions then
return str._error( 'function rep expects a number as second parameter, received "' .. ( frame.args[2] or '' ) .. '"' )
end
return string.rep( frame.args[1] or '', repetitions )
end
--[[
escapePattern
This function escapes special characters from a Lua string pattern. See [1]
for details on how patterns work.
[1] https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Patterns
Usage:
{{#invoke:String|escapePattern|pattern_string}}
Parameters
pattern_string: The pattern string to escape.
]]
function str.escapePattern( frame )
local pattern_str = frame.args[1]
if not pattern_str then
return str._error( 'No pattern string specified' )
end
local result = str._escapePattern( pattern_str )
return result
end
--[[
count
This function counts the number of occurrences of one string in another.
]]
function str.count(frame)
local args = str._getParameters(frame.args, {'source', 'pattern', 'plain'})
local source = args.source or ''
local pattern = args.pattern or ''
local plain = str._getBoolean(args.plain or true)
if plain then
pattern = str._escapePattern(pattern)
end
local _, count = mw.ustring.gsub(source, pattern, '')
return count
end
--[[
endswith
This function determines whether a string ends with another string.
]]
function str.endswith(frame)
local args = str._getParameters(frame.args, {'source', 'pattern'})
local source = args.source or ''
local pattern = args.pattern or ''
if pattern == '' then
-- All strings end with the empty string.
return "yes"
end
if mw.ustring.sub(source, -mw.ustring.len(pattern), -1) == pattern then
return "yes"
else
return ""
end
end
--[[
join
Join all non empty arguments together; the first argument is the separator.
Usage:
{{#invoke:String|join|sep|one|two|three}}
]]
function str.join(frame)
local args = {}
local sep
for _, v in ipairs( frame.args ) do
if sep then
if v ~= '' then
table.insert(args, v)
end
else
sep = v
end
end
return table.concat( args, sep or '' )
end
--[[
Helper function that populates the argument list given that user may need to use a mix of
named and unnamed parameters. This is relevant because named parameters are not
identical to unnamed parameters due to string trimming, and when dealing with strings
we sometimes want to either preserve or remove that whitespace depending on the application.
]]
function str._getParameters( frame_args, arg_list )
local new_args = {}
local index = 1
local value
for _, arg in ipairs( arg_list ) do
value = frame_args[arg]
if value == nil then
value = frame_args[index]
index = index + 1
end
new_args[arg] = value
end
return new_args
end
--[[
Helper function to handle error messages.
]]
function str._error( error_str )
local frame = mw.getCurrentFrame()
local error_category = frame.args.error_category or 'Errors reported by Module String'
local ignore_errors = frame.args.ignore_errors or false
local no_category = frame.args.no_category or false
if str._getBoolean(ignore_errors) then
return ''
end
local error_str = '<strong class="error">String Module Error: ' .. error_str .. '</strong>'
if error_category ~= '' and not str._getBoolean( no_category ) then
error_str = '[[Category:' .. error_category .. ']]' .. error_str
end
return error_str
end
--[[
Helper Function to interpret boolean strings
]]
function str._getBoolean( boolean_str )
local boolean_value
if type( boolean_str ) == 'string' then
boolean_str = boolean_str:lower()
if boolean_str == 'false' or boolean_str == 'no' or boolean_str == '0'
or boolean_str == '' then
boolean_value = false
else
boolean_value = true
end
elseif type( boolean_str ) == 'boolean' then
boolean_value = boolean_str
else
error( 'No boolean value found' )
end
return boolean_value
end
--[[
Helper function that escapes all pattern characters so that they will be treated
as plain text.
]]
function str._escapePattern( pattern_str )
return mw.ustring.gsub( pattern_str, "([%(%)%.%%%+%-%*%?%[%^%$%]])", "%%%1" )
end
return str
6df794dd52434e0f6a372c9918f5a9dedd15f579
Category:Category namespace templates
14
6
10
2023-05-30T20:29:23Z
Star>Alistair3149
0
Created page with "{{Category header|templates|category namespaces}} [[Category:Templates]]"
wikitext
text/x-wiki
{{Category header|templates|category namespaces}}
[[Category:Templates]]
6184a06473d378b690d4f5f4e627f2a40cd941b5
11
10
2024-01-11T08:30:42Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
{{Category header|templates|category namespaces}}
[[Category:Templates]]
6184a06473d378b690d4f5f4e627f2a40cd941b5
Module:User error
828
65
128
2023-06-01T04:08:37Z
star>Alistair3149
0
Created page with "-------------------------------------------------------------------------------- -- A less intimidating version of the built-in "error()" function, to help -- editors fix their mistakes when transcluding a template. -- -- @see [[wikia:w:c:Dev:Module:User error]] for a similar module. -------------------------------------------------------------------------------- local checkType = require("libraryUtil").checkType; return function (message, ...) checkType("Module:User..."
Scribunto
text/plain
--------------------------------------------------------------------------------
-- A less intimidating version of the built-in "error()" function, to help
-- editors fix their mistakes when transcluding a template.
--
-- @see [[wikia:w:c:Dev:Module:User error]] for a similar module.
--------------------------------------------------------------------------------
local checkType = require("libraryUtil").checkType;
return function (message, ...)
checkType("Module:User error", 1, message, "string");
local result = mw.text.tag(
"strong",
{ class="error" },
"Error: " .. message
);
local categories = {};
for i = 1, select("#", ...) do
local category = select(i, ...);
checkType("Module:User error", 1 + i, category, "string", true);
if (category and category ~= "") then
table.insert(categories, "[[Category:" .. category .. "]]");
end
end
return result .. table.concat(categories);
end;
a4101fc46477bcd3c5dd899b157bf34b216d820f
Module:Mbox
828
66
130
2023-06-06T03:02:53Z
star>Alistair3149
0
Scribunto
text/plain
local libraryUtil = require( 'libraryUtil' )
local checkType = libraryUtil.checkType
local mArguments -- lazily initialise [[Module:Arguments]]
local mError -- lazily initialise [[Module:Error]]
local p = {}
--- Helper function to throw error
--
-- @param msg string - Error message
--
-- @return string - Formatted error message in wikitext
local function makeWikitextError( msg )
mError = require( 'Module:Error' )
return mError.error{
message = 'Error: ' .. msg .. '.'
}
end
function p.mbox( frame )
local args = getArgs( frame )
local title = args[1] or args[ 'title' ]
local text = args[2] or args[ 'text' ]
if not s then
return p.makeWikitextError(
'no text specified',
'Template:Mbox#Errors',
args.category
)
end
return p._mbox( title, text, {
extraclasses = args.extraclasses,
icon = args.icon
} )
end
function p._mbox( title, text, options )
checkType( '_mbox', 1, title, 'string' )
checkType( '_mbox', 2, text, 'string' )
checkType( '_mbox', 3, options, 'table', true )
options = options or {}
local mbox = mw.html.create( 'div' )
local extraclasses
if type( options.extraclasses ) == 'string' then
extraclasses = options.extraclasses
end
mbox
:attr( 'role', 'presentation' )
:addClass( 'mbox' )
:addClass( extraclasses )
local mboxTitle = mbox:tag( 'div' ):addClass( 'mbox-title' )
if options.icon and type( options.icon ) == 'string' then
mboxTitle:tag( 'div' )
:addClass( 'mbox-icon metadata' )
:wikitext( '[[File:' .. options.icon .. '|14px|link=]]' )
:done()
:tag( 'div' )
:wikitext( title )
else
mboxTitle:wikitext( title )
end
mbox:tag( 'div' )
:addClass( 'mbox-text' )
:wikitext( text )
return mw.getCurrentFrame():extensionTag{
name = 'templatestyles', args = { src = 'Module:Mbox/styles.css' }
} .. tostring(mbox)
end
return p
3ac408bcf509952e70b97e64cb1062fe21f6c4bf
Template:Documentation/styles.css
10
53
104
2023-06-06T04:33:22Z
star>Alistair3149
0
text
text/plain
.documentation {
display: flex;
box-sizing: border-box;
flex-direction: column;
margin: 1.6rem 0;
padding-top: 1.6rem;
border-top: 1px solid;
border-color: var( --border-color-base );
border-radius: var( --border-radius--medium );
font-size: 0.875rem;
}
.documentation-header {
margin-top: 0;
margin-bottom: 0.8rem;
color: var( --color-base--emphasized );
font-size: 1.25rem;
font-weight: 600;
line-height: 1.2;
}
.documentation-subheader {
margin: -0.6rem 0 1.6rem 0;
color: var( --color-base--subtle );
font-size: 0.825rem;
}
.documentation-links {
margin: 0.3rem 0;
float: right;
font-family: monospace;
font-size: 0.875rem;
font-weight: 400;
}
.documentation-modulestats {
display: flex;
align-items: center;
justify-content: space-between;
}
.documentation-modulestats .wikitable{
margin: 0;
}
/**
* Tooltip styles used by DependencyList,
* shouldn't be here but it is only used here anyways
*/
.hatnote-container {
position: relative;
}
.tooltip-trigger {
padding: 0.2rem 0.5rem;
margin-right: 2px;
background: var( --color-primary );
border-radius: 100px;
color: #fff;
}
.tooltip-trigger:hover {
background: var( --color-primary--hover );
}
.tooltip-content {
position: absolute;
z-index: 1;
right: 0;
padding: 15px;
background-color: var( --color-surface-1 );
border-radius: var( --border-radius--medium );
box-shadow: 0 14px 28px rgba( 0, 0, 0, 0.06 ), 0 10px 10px rgba( 0, 0, 0, 0.06 );
visibility: hidden;
}
.tooltip-content > ol {
margin-top: 0;
margin-left: 1.2rem;
}
.tooltip-content:hover,
.tooltip-trigger:hover + .tooltip-content {
visibility: visible;
}
7cedb77e3d7d2055318ceaf9b5e24342b73243ce
Template:Infobox/doc
10
61
120
2023-06-07T16:27:07Z
star>Alistair3149
0
deprecate Template:Wikipedia template
wikitext
text/x-wiki
{{Documentation|fromWikipedia=true}}
<!-- EDIT TEMPLATE DOCUMENTATION BELOW THIS LINE -->
Please refer to {{t|Infobox}} on Wikipedia for more details
<noinclude></noinclude>
<includeonly>
<!-- Template catergories go here -->
[[Category:Infobox templates]]
</includeonly>
04b27574c3656318415ace03777bcc2a3c16ef74
Module:Mbox/styles.css
828
67
132
2023-06-09T03:29:19Z
star>Alistair3149
0
text
text/plain
.mbox {
position: relative;
display: flex;
flex-direction: column;
margin-top: var( --space-xs );
margin-bottom: var( --space-md );
background-color: var( --color-surface-2 );
border-radius: var( --border-radius--medium );
color: var( --color-base--subtle );
font-size: 0.875rem;
line-height: var( --line-height-xs );
}
.mbox.mbox-high {
/* FIXME: Update back to Citzen CSS var when patched */
background-color: rgba( 221, 51, 51, 0.1 );
}
.mbox.mbox-med {
/* FIXME: Update back to Citzen CSS var when patched */
background-color: rgba( 255, 204, 51, 0.1 );
}
.mbox-title {
display: flex;
align-items: center;
padding: var( --space-sm ) var( --space-md );
}
.mbox-icon img {
width: 14px;
height: auto;
margin-right: var( --space-xs );
opacity: 0.5;
}
.mbox-text {
position: absolute;
top: 100%;
z-index: 10;
padding: var( --space-md );
width: 100%;
box-sizing: border-box;
background-color: var( --color-surface-1 );
border-bottom-left-radius: var( --border-radius--medium );
border-bottom-right-radius: var( --border-radius--medium );
box-shadow: var( --box-shadow-dialog );
opacity: 0;
visibility: hidden;
}
.mbox:hover {
/* Merge with popup */
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
box-shadow: var( --box-shadow-dialog );
}
.mbox:hover .mbox-text {
opacity: 1;
visibility: visible;
}
/* Dark mode */
html.skin-citizen-dark .mbox-icon img {
filter: invert( 1 );
}
6e8c0951d8f9dcde54a751e8564916bec21071ce
Category:SMW templates
14
30
58
2023-06-20T02:34:07Z
Star>Alistair3149
0
Created page with "{{Category header|templates|Semantic MediaWiki}} [[Category:Templates]]"
wikitext
text/x-wiki
{{Category header|templates|Semantic MediaWiki}}
[[Category:Templates]]
a92eae2d4d80d16870caa41abea5041ce8d46b04
59
58
2024-01-11T08:30:52Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
{{Category header|templates|Semantic MediaWiki}}
[[Category:Templates]]
a92eae2d4d80d16870caa41abea5041ce8d46b04
Module:Format link
828
63
124
2023-06-24T17:00:45Z
star>Alistair3149
0
Sync with upstream
Scribunto
text/plain
-- Imported from: https://en.wikipedia.org/wiki/Module:Format_link
--------------------------------------------------------------------------------
-- Format link
--
-- Makes a wikilink from the given link and display values. Links are escaped
-- with colons if necessary, and links to sections are detected and displayed
-- with " § " as a separator rather than the standard MediaWiki "#". Used in
-- the {{format link}} template.
--------------------------------------------------------------------------------
local libraryUtil = require('libraryUtil')
local checkType = libraryUtil.checkType
local checkTypeForNamedArg = libraryUtil.checkTypeForNamedArg
local mArguments -- lazily initialise [[Module:Arguments]]
local mError -- lazily initialise [[Module:Error]]
local yesno -- lazily initialise [[Module:Yesno]]
local p = {}
--------------------------------------------------------------------------------
-- Helper functions
--------------------------------------------------------------------------------
local function getArgs(frame)
-- Fetches the arguments from the parent frame. Whitespace is trimmed and
-- blanks are removed.
mArguments = require('Module:Arguments')
return mArguments.getArgs(frame, {parentOnly = true})
end
local function removeInitialColon(s)
-- Removes the initial colon from a string, if present.
return s:match('^:?(.*)')
end
local function maybeItalicize(s, shouldItalicize)
-- Italicize s if s is a string and the shouldItalicize parameter is true.
if s and shouldItalicize then
return '<i>' .. s .. '</i>'
else
return s
end
end
local function parseLink(link)
-- Parse a link and return a table with the link's components.
-- These components are:
-- - link: the link, stripped of any initial colon (always present)
-- - page: the page name (always present)
-- - section: the page name (may be nil)
-- - display: the display text, if manually entered after a pipe (may be nil)
link = removeInitialColon(link)
-- Find whether a faux display value has been added with the {{!}} magic
-- word.
local prePipe, display = link:match('^(.-)|(.*)$')
link = prePipe or link
-- Find the page, if it exists.
-- For links like [[#Bar]], the page will be nil.
local preHash, postHash = link:match('^(.-)#(.*)$')
local page
if not preHash then
-- We have a link like [[Foo]].
page = link
elseif preHash ~= '' then
-- We have a link like [[Foo#Bar]].
page = preHash
end
-- Find the section, if it exists.
local section
if postHash and postHash ~= '' then
section = postHash
end
return {
link = link,
page = page,
section = section,
display = display,
}
end
local function formatDisplay(parsed, options)
-- Formats a display string based on a parsed link table (matching the
-- output of parseLink) and an options table (matching the input options for
-- _formatLink).
local page = maybeItalicize(parsed.page, options.italicizePage)
local section = maybeItalicize(parsed.section, options.italicizeSection)
if (not section) then
return page
elseif (not page) then
return mw.ustring.format('§ %s', section)
else
return mw.ustring.format('%s § %s', page, section)
end
end
local function missingArgError(target)
mError = require('Module:Error')
return mError.error{message =
'Error: no link or target specified! ([[' .. target .. '#Errors|help]])'
}
end
--------------------------------------------------------------------------------
-- Main functions
--------------------------------------------------------------------------------
function p.formatLink(frame)
-- The formatLink export function, for use in templates.
yesno = require('Module:Yesno')
local args = getArgs(frame)
local link = args[1] or args.link
local target = args[3] or args.target
if not (link or target) then
return missingArgError('Template:Format link')
end
return p._formatLink{
link = link,
display = args[2] or args.display,
target = target,
italicizePage = yesno(args.italicizepage),
italicizeSection = yesno(args.italicizesection),
categorizeMissing = args.categorizemissing
}
end
function p._formatLink(options)
-- The formatLink export function, for use in modules.
checkType('_formatLink', 1, options, 'table')
local function check(key, expectedType) --for brevity
checkTypeForNamedArg(
'_formatLink', key, options[key], expectedType or 'string', true
)
end
check('link')
check('display')
check('target')
check('italicizePage', 'boolean')
check('italicizeSection', 'boolean')
check('categorizeMissing')
-- Normalize link and target and check that at least one is present
if options.link == '' then options.link = nil end
if options.target == '' then options.target = nil end
if not (options.link or options.target) then
return missingArgError('Module:Format link')
end
local parsed = parseLink(options.link)
local display = options.display or parsed.display
local catMissing = options.categorizeMissing
local category = ''
-- Find the display text
if not display then display = formatDisplay(parsed, options) end
-- Handle the target option if present
if options.target then
local parsedTarget = parseLink(options.target)
parsed.link = parsedTarget.link
parsed.page = parsedTarget.page
end
-- Test if page exists if a diagnostic category is specified
if catMissing and (mw.ustring.len(catMissing) > 0) then
local title = nil
if parsed.page then title = mw.title.new(parsed.page) end
if title and (not title.isExternal) then
local success, exists = pcall(function() return title.exists end)
if success and not exists then
category = mw.ustring.format('[[Category:%s]]', catMissing)
end
end
end
-- Format the result as a link
if parsed.link == display then
return mw.ustring.format('[[:%s]]%s', parsed.link, category)
else
return mw.ustring.format('[[:%s|%s]]%s', parsed.link, display, category)
end
end
--------------------------------------------------------------------------------
-- Derived convenience functions
--------------------------------------------------------------------------------
function p.formatPages(options, pages)
-- Formats an array of pages using formatLink and the given options table,
-- and returns it as an array. Nil values are not allowed.
local ret = {}
for i, page in ipairs(pages) do
ret[i] = p._formatLink{
link = page,
categorizeMissing = options.categorizeMissing,
italicizePage = options.italicizePage,
italicizeSection = options.italicizeSection
}
end
return ret
end
return p
410e1254e813fed6fe2f04598836316a197db2d1
Module:Yesno
828
51
100
2023-06-24T17:05:19Z
star>Alistair3149
0
Sync with upstream
Scribunto
text/plain
-- Imported from: https://en.wikipedia.org/wiki/Module:Yesno
-- Function allowing for consistent treatment of boolean-like wikitext input.
-- It works similarly to the template {{yesno}}.
return function (val, default)
-- If your wiki uses non-ascii characters for any of "yes", "no", etc., you
-- should replace "val:lower()" with "mw.ustring.lower(val)" in the
-- following line.
val = type(val) == 'string' and val:lower() or val
if val == nil then
return nil
elseif val == true
or val == 'yes'
or val == 'y'
or val == 'true'
or val == 't'
or val == 'on'
or val == 'ja'
or tonumber(val) == 1
then
return true
elseif val == false
or val == 'no'
or val == 'n'
or val == 'false'
or val == 'f'
or val == 'off'
or val == 'nein'
or tonumber(val) == 0
then
return false
else
return default
end
end
4cb9790f60303552aa5d331d9ab52f0a3e1f266e
Module:Array
828
62
122
2023-06-24T17:23:20Z
star>Alistair3149
0
Scribunto
text/plain
-- Imported from: https://runescape.wiki/w/Module:Array
local libraryUtil = require('libraryUtil')
local checkType = libraryUtil.checkType
local checkTypeMulti = libraryUtil.checkTypeMulti
---@class Array
---@operator call(any[]): Array
---@operator concat(any[]): Array
---@operator concat(number|string|function): string
---@operator unm: Array
---@operator add(number|number[]|Array): Array
---@operator sub(number|number[]|Array): Array
---@operator mul(number|number[]|Array): Array
---@operator div(number|number[]|Array): Array
---@operator pow(number|number[]|Array): Array
local Array = {
pop = table.remove
}
Array.__index = Array
setmetatable(Array, {
__index = table,
__call = function (_, arr)
return Array.new(arr)
end
})
-- function Array.__tostring(arr)
-- -- local dumpObject = require('Module:Logger').dumpObject
-- require 'log'
-- local dumpObject = dumpObject
-- local mt = getmetatable(arr)
-- setmetatable(arr, nil)
-- local str = dumpObject(arr, {clean=true, collapseLimit=100})
-- setmetatable(arr, mt)
-- return str
-- end
function Array.__concat(lhs, rhs)
if type(lhs) == 'table' and type(rhs) == 'table' then
local res = {}
for i = 1, #lhs do
res[i] = lhs[i]
end
local l = #lhs
for i = 1, #rhs do
res[i + l] = rhs[i]
end
return setmetatable(res, getmetatable(lhs) or getmetatable(rhs))
else
return tostring(lhs) .. tostring(rhs)
end
end
function Array.__unm(arr)
return Array.map(arr, function(x) return -x end)
end
---@param lhs number|number[]|Array
---@param rhs number|number[]|Array
---@param funName string
---@param opName string
---@param fun fun(lhs: number, rhs: number): number
---@return Array
local function mathTemplate(lhs, rhs, funName, opName, fun)
checkTypeMulti('Module:Array.' .. funName, 1, lhs, {'number', 'table'})
checkTypeMulti('Module:Array.' .. funName, 2, rhs, {'number', 'table'})
local res = {}
if type(lhs) == 'number' then
for i = 1, #rhs do
res[i] = fun(lhs, rhs[i])
end
elseif type(rhs) == 'number' then
for i = 1, #lhs do
res[i] = fun(lhs[i], rhs)
end
else
assert(#lhs == #rhs, string.format('Elementwise %s failed because arrays have different sizes (left: %d, right: %d)', opName, #lhs, #rhs))
for i = 1, #lhs do
res[i] = fun(lhs[i], rhs[i])
end
end
return setmetatable(res, getmetatable(lhs) or getmetatable(rhs))
end
function Array.__add(lhs, rhs)
return mathTemplate(lhs, rhs, '__add', 'addition', function(x, y) return x + y end)
end
function Array.__sub(lhs, rhs)
return mathTemplate(lhs, rhs, '__sub', 'substraction', function(x, y) return x - y end)
end
function Array.__mul(lhs, rhs)
return mathTemplate(lhs, rhs, '__mul', 'multiplication', function(x, y) return x * y end)
end
function Array.__div(lhs, rhs)
return mathTemplate(lhs, rhs, '__div', 'division', function(x, y) return x / y end)
end
function Array.__pow(lhs, rhs)
return mathTemplate(lhs, rhs, '__pow', 'exponentiation', function(x, y) return x ^ y end)
end
function Array.__eq(lhs, rhs)
if #lhs ~= #rhs then
return false
end
for i = 1, #lhs do
if lhs[i] ~= rhs[i] then
return false
end
end
return true
end
---Behaviour depends on the value of `fn`:
---* `nil` - Checks that the array doesn't contain any **false** elements.
---* `fun(elem: any, i?: integer): boolean` - Returns **true** if `fn` returns **true** for every element.
---* `number` | `table` | `boolean` - Checks that all elements in `arr` are equal to this value.
---@param arr any[]
---@param fn? any
---@return boolean
function Array.all(arr, fn)
checkType('Module:Array.all', 1, arr, 'table')
if fn == nil then fn = function(item) return item end end
if type(fn) ~= 'function' then
local val = fn
fn = function(item) return item == val end
end
local i = 1
while arr[i] ~= nil do
---@diagnostic disable-next-line: redundant-parameter
if not fn(arr[i], i) then
return false
end
i = i + 1
end
return true
end
---Behaviour depends on the value of `fn`:
---* `nil` - Checks that the array contains at least one non **false** element.
---* `fun(elem: any, i?: integer): boolean` - Returns **true** if `fn` returns **true** for at least one element.
---* `number` | `table` | `boolean` - Checks that `arr` contains this value.
---@param arr any[]
---@param fn? any
---@return boolean
function Array.any(arr, fn)
checkType('Module:Array.any', 1, arr, 'table')
if fn == nil then fn = function(item) return item end end
if type(fn) ~= 'function' then
local val = fn
fn = function(item) return item == val end
end
local i = 1
while arr[i] ~= nil do
---@diagnostic disable-next-line: redundant-parameter
if fn(arr[i], i) then
return true
end
i = i + 1
end
return false
end
---Recursively removes all metatables.
---@param arr any[]
---@return any[]
function Array.clean(arr)
checkType('Module:Array.clean', 1, arr, 'table')
for i = 1, #arr do
if type(arr[i]) == 'table' then
Array.clean(arr[i])
end
end
setmetatable(arr, nil)
return arr
end
---Make a copy of the input table. Preserves metatables.
---@generic T: any[]
---@param arr T
---@param deep? boolean # Recursively clone subtables if **true**.
---@return T
function Array.clone(arr, deep)
checkType('Module:Array.clone', 1, arr, 'table')
checkType('Module:Array.clone', 2, deep, 'boolean', true)
local res = {}
for i = 1, #arr do
if deep == true and type(arr[i]) == 'table' then
res[i] = Array.clone(arr[i], true)
else
res[i] = arr[i]
end
end
return setmetatable(res, getmetatable(arr))
end
---Check if `arr` contains `val`.
---@param arr any[]
---@param val any
---@return boolean
function Array.contains(arr, val)
checkType('Module:Array.contains', 1, arr, 'table')
for i = 1, #arr do
if arr[i] == val then
return true
end
end
return false
end
---Check if `arr` contains any of the values in the table `t`.
---@param arr any[]
---@param t any[]
---@return boolean
function Array.containsAny(arr, t)
checkType('Module:Array.containsAny', 1, arr, 'table')
checkType('Module:Array.containsAny', 2, t, 'table')
local lookupTbl = {}
for i = 1, #t do
lookupTbl[t[i]] = true
end
for i = 1, #arr do
if lookupTbl[arr[i]] then
return true
end
end
return false
end
---Check if `arr` contains all values in the table `t`.
---@param arr any[]
---@param t any[]
---@return boolean
function Array.containsAll(arr, t)
checkType('Module:Array.containsAll', 1, arr, 'table')
checkType('Module:Array.containsAll', 2, t, 'table')
local lookupTbl = {}
local l = #t
local trueCount = 0
for i = 1, l do
lookupTbl[t[i]] = false
end
for i = 1, #arr do
if lookupTbl[arr[i]] == false then
lookupTbl[arr[i]] = true
trueCount = trueCount + 1
end
if trueCount == l then
return true
end
end
return false
end
---Convolute two number arrays.
---@generic T: number[]
---@param x T
---@param y T
---@return T
function Array.convolve(x, y)
checkType('Module:Array.convolve', 1, x, 'table')
checkType('Module:Array.convolve', 2, y, 'table')
local z = {}
local xLen, yLen = #x, #y
for j = 1, (xLen + yLen - 1) do
local sum = 0
for k = math.max(1, j - yLen + 1), math.min(xLen, j) do
sum = sum + x[k] * y[j-k+1]
end
z[j] = sum
end
return setmetatable(z, getmetatable(x) or getmetatable(y))
end
---Remove **nil** values from `arr` while preserving order.
---@generic T: any[]
---@param arr T
---@return T
function Array.condenseSparse(arr)
checkType('Module:Array.condenseSparse', 1, arr, 'table')
local keys = {}
local res = {}
local l = 0
for k in pairs(arr) do
l = l + 1
keys[l] = k
end
table.sort(keys)
for i = 1, l do
res[i] = arr[keys[i]]
end
return setmetatable(res, getmetatable(arr))
end
---Behaviour depends on value of `val`:
---* `nil` - Counts the number of non **false** elements.
---* `fun(elem: any): boolean` - Count the number of times the function returned **true**.
---* `boolean` | `number` | `table` - Counts the number of times this value occurs in `arr`.
---@param arr any[]
---@param val? any
---@return integer
function Array.count(arr, val)
checkType('Module:Array.count', 1, arr, 'table')
if val == nil then val = function(item) return item end end
if type(val) ~= 'function' then
local _val = val
val = function(item) return item == _val end
end
local count = 0
for i = 1, #arr do
if val(arr[i]) then
count = count + 1
end
end
return count
end
---Differentiate the array
---@generic T: number[]
---@param arr T
---@param order number? # Oder of the differentiation. Default is 1.
---@return T # Length is `#arr - order`
function Array.diff(arr, order)
checkType('Module:Array.diff', 1, arr, 'table')
checkType('Module:Array.diff', 2, order, 'number', true)
local res = {}
for i = 1, #arr - 1 do
res[i] = arr[i+1] - arr[i]
end
if order and order > 1 then
return Array.diff(res, order - 1)
end
return setmetatable(res, getmetatable(arr))
end
---Loops over `arr` and passes each element as the first argument to `fn`. This function returns nothing.
---@param arr any[]
---@param fn fun(elem: any, i?: integer)
function Array.each(arr, fn)
checkType('Module:Array.each', 1, arr, 'table')
checkType('Module:Array.each', 2, fn, 'function')
local i = 1
while arr[i] ~= nil do
fn(arr[i], i)
i = i + 1
end
end
---Makes a copy of `arr` with only elements for which `fn` returned **true**.
---@generic T: any[]
---@param arr T
---@param fn fun(elem: any, i?: integer): boolean
---@return T
function Array.filter(arr, fn)
checkType('Module:Array.filter', 1, arr, 'table')
checkType('Module:Array.filter', 2, fn, 'function')
local r = {}
local len = 0
local i = 1
while arr[i] ~= nil do
if fn(arr[i], i) then
len = len + 1
r[len] = arr[i]
end
i = i + 1
end
return setmetatable(r, getmetatable(arr))
end
---Find the first elements for which `fn` returns **true**.
---@param arr any[]
---@param fn any # A value to look for or a function of the form `fun(elem: any, i?: integer): boolean`.
---@param default? any # Value to return if no element passes the test.
---@return any? elem # The first element that passed the test.
---@return integer? i # The index of the item that passed the test.
function Array.find(arr, fn, default)
checkType('Module:Array.find', 1, arr, 'table')
checkTypeMulti('Module:Array.find_index', 2, fn, {'function', 'table', 'number', 'boolean'})
if type(fn) ~= 'function' then
local _val = fn
fn = function(item) return item == _val end
end
local i = 1
while arr[i] ~= nil do
---@diagnostic disable-next-line: redundant-parameter
if fn(arr[i], i) then
return arr[i], i
end
i = i + 1
end
return default, nil
end
---Find the index of `val`.
---@param arr any[]
---@param val any # A value to look for or a function of the form `fun(elem: any, i?: integer): boolean`.
---@param default? any # Value to return if no element passes the test.
---@return integer?
function Array.find_index(arr, val, default)
checkType('Module:Array.find_index', 1, arr, 'table')
checkTypeMulti('Module:Array.find_index', 2, val, {'function', 'table', 'number', 'boolean'})
if type(val) ~= 'function' then
local _val = val
val = function(item) return item == _val end
end
local i = 1
while arr[i] ~= nil do
---@diagnostic disable-next-line: redundant-parameter
if val(arr[i], i) then
return i
end
i = i + 1
end
return default
end
---Extracts a subset of `arr`.
---@generic T: any[]
---@param arr T
---@param indexes integer|integer[] # Indexes of the elements.
---@return T
function Array.get(arr, indexes)
checkType('Module:Array.set', 1, arr, 'table')
checkTypeMulti('Module:Array.set', 2, indexes, {'table', 'number'})
if type(indexes) == 'number' then
indexes = {indexes}
end
local res = {}
for i = 1, #indexes do
res[i] = arr[indexes[i]]
end
return setmetatable(res, getmetatable(arr))
end
---Integrates the array. Effectively does $\left\{\sum^{n}_{start}{arr[n]} \,\Bigg|\, n \in [start, stop]\right\}$.
---@generic T: number[]
---@param arr T # number[]
---@param start? integer # Index where to start the summation. Defaults to 1.
---@param stop? integer # Index where to stop the summation. Defaults to #arr.
---@return T
function Array.int(arr, start, stop)
checkType('Module:Array.int', 1, arr, 'table')
checkType('Module:Array.int', 2, start, 'number', true)
checkType('Module:Array.int', 3, stop, 'number', true)
local res = {}
start = start or 1
stop = stop or #arr
res[1] = arr[start]
for i = 1, stop - start do
res[i+1] = res[i] + arr[start + i]
end
return setmetatable(res, getmetatable(arr))
end
---Returns an array with elements that are present in both tables.
---@generic T: any[]
---@param arr1 T
---@param arr2 T
---@return T
function Array.intersect(arr1, arr2)
checkType('Module:Array.intersect', 1, arr1, 'table')
checkType('Module:Array.intersect', 2, arr2, 'table')
local arr2Elements = {}
local res = {}
local len = 0
Array.each(arr2, function(item) arr2Elements[item] = true end)
Array.each(arr1, function(item)
if arr2Elements[item] then
len = len + 1
res[len] = item
end
end)
return setmetatable(res, getmetatable(arr1) or getmetatable(arr2))
end
---Checks if the two inputs have at least one element in common.
---@param arr1 any[]
---@param arr2 any[]
---@return boolean
function Array.intersects(arr1, arr2)
checkType('Module:Array.intersects', 1, arr1, 'table')
checkType('Module:Array.intersects', 2, arr2, 'table')
local small = {}
local large
if #arr1 <= #arr2 then
Array.each(arr1, function(item) small[item] = true end)
large = arr2
else
Array.each(arr2, function(item) small[item] = true end)
large = arr1
end
return Array.any(large, function(item) return small[item] end)
end
---Inserts values into `arr`.
---@generic T: any[]
---@param arr T
---@param val any # If `val` is an array and `unpackVal` is **true** then the individual elements of `val` are inserted.
---@param index? integer # Location to start the insertion. Default is at the end of `arr`.
---@param unpackVal? boolean # Default is **false**.
---@return T
---@overload fun(arr: T, val: any, unpackVal: boolean): T
function Array.insert(arr, val, index, unpackVal)
checkType('Module:Array.insert', 1, arr, 'table')
checkTypeMulti('Module:Array.insert', 3, index, {'number', 'boolean', 'nil'})
checkType('Module:Array.insert', 4, unpackVal, 'boolean', true)
if type(index) == 'boolean' then
unpackVal, index = index, nil
end
local len = #arr
index = index or (len + 1)
local mt = getmetatable(arr)
setmetatable(arr, nil)
if type(val) == 'table' and unpackVal then
local len2 = #val
for i = 0, len - index do
arr[len + len2 - i] = arr[len - i]
end
for i = 0, len2 - 1 do
arr[index + i] = val[i + 1]
end
else
table.insert(arr, index, val)
end
return setmetatable(arr, mt)
end
---Returns the last element of `arr`.
---@param arr any[]
---@param offset? integer
---@return any
function Array.last(arr, offset)
checkType('Module:Array.last', 1, arr, 'table')
checkType('Module:Array.last', 2, offset, 'number', true)
return arr[#arr + offset]
end
---Returns a new table were each element of `arr` is modified by `fn`.
---@generic T: any[]
---@param arr T
---@param fn fun(elem: any, i?: integer): any # First argument is the current element, the second argument is the index of the current element.
---@return T
function Array.map(arr, fn)
checkType('Module:Array.map', 1, arr, 'table')
checkType('Module:Array.map', 2, fn, 'function')
local len = 0
local r = {}
local i = 1
while arr[i] ~= nil do
local tmp = fn(arr[i], i)
if tmp ~= nil then
len = len + 1
r[len] = tmp
end
i = i + 1
end
return setmetatable(r, getmetatable(arr))
end
---Find the element for which `fn` returned the largest value.
---@param arr any[]
---@param fn fun(elem: any): any # The returned value needs to be comparable using the `<` operator.
---@return any elem # The element with the largest `fn` value.
---@return integer i # The index of this element.
function Array.max_by(arr, fn)
checkType('Module:Array.max_by', 1, arr, 'table')
checkType('Module:Array.max_by', 2, fn, 'function')
return unpack(Array.reduce(arr, function(new, old, i)
local y = fn(new)
return y > old[2] and {new, y, i} or old
end, {nil, -math.huge}))
end
---Find the largest value in the array.
---@param arr any[] # The values need to be comparable using the `<` operator.
---@return any elem
---@return integer i # The index of the largest value.
function Array.max(arr)
checkType('Module:Array.max', 1, arr, 'table')
local val, _, i = Array.max_by(arr, function(x) return x end)
return val, i
end
---Find the smallest value in the array.
---@param arr any[] # The values need to be comparable using the `<` operator.
---@return any elem
---@return integer i # The index of the smallest value.
function Array.min(arr)
checkType('Module:Array.min', 1, arr, 'table')
local val, _, i = Array.max_by(arr, function(x) return -x end)
return val, i
end
---Turn the input table into an Array. This makes it possible to use the colon `:` operator to access the Array methods.
---
---It also enables the use of math operators with the array.
---```
---local x = arr.new{ 1, 2, 3 }
---local y = arr{ 4, 5, 6 } -- Alternative notation
---
---print( -x ) --> { -1, -2, -3 }
---print( x + 2 ) --> { 3, 4, 5 }
---print( x - 2 ) --> { -1, 0, 1 }
---print( x * 2 ) --> { 2, 4, 6 }
---print( x / 2 ) --> { 0.5, 1, 1.5 }
---print( x ^ 2 ) --> { 1, 4, 9 }
---
---print( x + y ) --> { 5, 7, 9 }
---print( x .. y ) --> { 1, 2, 3, 4, 5, 6 }
---print( (x .. y):reject{3, 4, 5} ) --> { 1, 2, 6 }
---print( x:sum() ) --> 6
---
---print( x:update( {1, 3}, y:get{2, 3} * 2 ) ) --> { 10, 2, 12 }
---```
---@param arr? any[]
---@return Array
function Array.new(arr)
local obj = arr or {}
for _, v in pairs(obj) do
if type(v) == 'table' then
Array.new(v)
end
end
if getmetatable(obj) == nil then
setmetatable(obj, Array)
end
return obj
end
---Creates an object that returns a value that is `step` higher than the previous value each time it gets called.
---
---The stored value can be read without incrementing by reading the `val` field.
---
---A new stored value can be set through the `val` field.
---
---A new step size can be set through the `step` field.
---```
---local inc = arr.newIncrementor(10, 5)
---print( inc() ) --> 10
---print( inc() ) --> 15
---print( inc.val ) --> 15
---inc.val = 100
---inc.step = 20
---print( inc.val ) --> 100
---print( inc() ) --> 120
---```
---@param start? number # Default is 1.
---@param step? number # Default is 1.
---@return Incrementor
function Array.newIncrementor(start, step)
checkType('Module:Array.newIncrementor', 1, start, 'number', true)
checkType('Module:Array.newIncrementor', 2, step, 'number', true)
step = step or 1
local n = (start or 1) - step
---@class Incrementor
local obj = {}
return setmetatable(obj, {
__call = function() n = n + step return n end,
__tostring = function() return n end,
__index = function() return n end,
__newindex = function(self, k, v)
if k == 'step' and type(v) == 'number' then
step = v
elseif type(v) == 'number' then
n = v
end
end,
__concat = function(x, y) return tostring(x) .. tostring(y) end
})
end
---Returns a range of numbers.
---@param start number # Start value inclusive.
---@param stop number # Stop value inclusive for integers, exclusive for floats.
---@param step? number # Default is 1.
---@return Array
---@overload fun(stop: number): Array
function Array.range(start, stop, step)
checkType('Module:Array.range', 1, start, 'number')
checkType('Module:Array.range', 2, stop, 'number', true)
checkType('Module:Array.range', 3, step, 'number', true)
local arr = {}
local len = 0
if not stop then
stop = start
start = 1
end
for i = start, stop, step or 1 do
len = len + 1
arr[len] = i
end
return setmetatable(arr, Array)
end
---Condenses the array into a single value.
---
---For each element `fn` is called with the current element, the current accumulator, and the current element index. The returned value of `fn` becomes the accumulator for the next element.
---
---If no `accumulator` value is given at the start then the first element off `arr` becomes the accumulator and the iteration starts from the second element.
---```
---local t = { 1, 2, 3, 4 }
---local sum = arr.reduce( t, function(elem, acc) return acc + elem end ) -- sum == 10
---```
---@param arr any[]
---@param fn fun(elem: any, acc: any, i?: integer): any # The result of this function becomes the `acc` for the next element.
---@param accumulator? any
---@return any # This is the last accumulator value.
function Array.reduce(arr, fn, accumulator)
checkType('Module:Array.reduce', 1, arr, 'table')
checkType('Module:Array.reduce', 2, fn, 'function')
local acc = accumulator
local i = 1
if acc == nil then
acc = arr[1]
i = 2
end
while arr[i] ~= nil do
acc = fn(arr[i], acc, i)
i = i + 1
end
return acc
end
---Make a copy off `arr` with certain values removed.
---
---Behaviour for different values of `val`:
---* `boolean` | `number` - Remove values equal to this.
---* `table` - Remove all values in this table.
---* `fun(elem: any, i?: integer): boolean` - Remove elements for which the functions returns **true**.
---@generic T: any[]
---@param arr T
---@param val table|function|number|boolean
---@return T
function Array.reject(arr, val)
checkType('Module:Array.reject', 1, arr, 'table')
checkTypeMulti('Module:Array.reject', 2, val, {'function', 'table', 'number', 'boolean'})
if type(val) ~= 'function' and type(val) ~= 'table' then
val = {val}
end
local r = {}
local len = 0
if type(val) == 'function' then
local i = 1
while arr[i] ~= nil do
if not val(arr[i], i) then
len = len + 1
r[len] = arr[i]
end
i = i + 1
end
else
local rejectMap = {}
Array.each(val --[[@as any[] ]], function(item) rejectMap[item] = true end)
local i = 1
while arr[i] ~= nil do
if not rejectMap[arr[i]] then
len = len + 1
r[len] = arr[i]
end
i = i + 1
end
end
return setmetatable(r, getmetatable(arr))
end
---Returns an Array with `val` repeated `n` times.
---@param val any
---@param n integer
---@return Array
function Array.rep(val, n)
checkType('Module:Array.rep', 2, n, 'number')
local r = {}
for i = 1, n do
r[i] = val
end
return setmetatable(r, Array)
end
---Condenses the array into a single value while saving every accumulator value.
---
---For each element `fn` is called with the current element, the current accumulator, and the current element index. The returned value of `fn` becomes the accumulator for the next element.
---
---If no `accumulator` value is given at the start then the first element off `arr` becomes the accumulator and the iteration starts from the second element.
---```
---local t = { 1, 2, 3, 4 }
---local x = arr.scan( t, function(elem, acc) return acc + elem end ) -- x = { 1, 3, 6, 10 }
---```
---@generic T: any[]
---@param arr T
---@param fn fun(elem: any, acc: any, i?: integer): any # Returned value becomes the accumulator for the next element.
---@param accumulator? any
---@return T
function Array.scan(arr, fn, accumulator)
checkType('Module:Array.scan', 1, arr, 'table')
checkType('Module:Array.scan', 2, fn, 'function')
local acc = accumulator
local r = {}
local i = 1
while arr[i] ~= nil do
if i == 1 and not accumulator then
acc = arr[i]
else
acc = fn(arr[i], acc, i)
end
r[i] = acc
i = i + 1
end
return setmetatable(r, getmetatable(arr))
end
---Update a range of index with a range of values.
---
---If if only one value is given but multiple indexes than that value is set for all those indexes.
---
---If `values` is a table then it must of the same length as `indexes`.
---@generic T: any[]
---@param arr T
---@param indexes integer|integer[]
---@param values any|any[]
---@return T
function Array.set(arr, indexes, values)
checkType('Module:Array.set', 1, arr, 'table')
checkTypeMulti('Module:Array.set', 2, indexes, {'table', 'number'})
local mt = getmetatable(arr)
setmetatable(arr, nil)
if type(indexes) == 'number' then
indexes = {indexes}
end
if type(values) == 'table' then
assert(#indexes == #values, string.format("Module:Array.set: 'indexes' and 'values' arrays are not equal length (#indexes = %d, #values = %d)", #indexes, #values))
for i = 1, #indexes do
arr[indexes[i]] = values[i]
end
else
for i = 1, #indexes do
arr[indexes[i]] = values
end
end
return setmetatable(arr, mt)
end
---Extract a subtable from `arr`.
---@generic T: any[]
---@param arr T
---@param start integer # Start index. Use negative values to count form the end of the array.
---@param stop integer # Stop index. Use negative values to count form the end of the array.
---@return T
---@overload fun(arr: T, stop: integer): T
function Array.slice(arr, start, stop)
checkType('Module:Array.slice', 1, arr, 'table')
checkType('Module:Array.slice', 2, start, 'number', true)
checkType('Module:Array.slice', 3, stop, 'number', true)
start = start or #arr
if start < 0 then
start = #arr + start
end
if stop == nil then
stop = start
start = 1
end
if stop < 0 then
stop = #arr + stop
end
local r = {}
local len = 0
for i = start, stop do
len = len + 1
r[len] = arr[i]
end
return setmetatable(r, getmetatable(arr))
end
---Split `arr` into two arrays.
---@generic T: any[]
---@param arr T
---@param index integer # Index to split on.
---@return T x # [1, index]
---@return T y # [index + 1, #arr]
function Array.split(arr, index)
checkType('Module:Array.split', 1, arr, 'table')
checkType('Module:Array.split', 2, index, 'number')
local x = {}
local y = {}
for i = 1, #arr do
table.insert(i <= index and x or y, arr[i])
end
return setmetatable(x, getmetatable(arr)), setmetatable(y, getmetatable(arr))
end
---Returns the sum of all elements of `arr`.
---@param arr number[]
---@return number
function Array.sum(arr)
checkType('Module:Array.sum', 1, arr, 'table')
local res = 0
for i = 1, #arr do
res = res + arr[i]
end
return res
end
---Extract a subtable from `arr`.
---@generic T: any[]
---@param arr T
---@param count integer # Length of the subtable.
---@param start? integer # Start index. Default is 1.
---@return T
function Array.take(arr, count, start)
checkType('Module:Array.take', 1, arr, 'table')
checkType('Module:Array.take', 2, count, 'number')
checkType('Module:Array.take', 3, start, 'number', true)
local x = {}
start = start or 1
for i = start, math.min(#arr, count + start - 1) do
table.insert(x, arr[i])
end
return setmetatable(x, getmetatable(arr))
end
---Extract a subtable from `arr`.
---```
---local t = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
---local x = arr.take_every( t, 2 ) --> x = { 1, 3, 5, 7, 9 }
---local x = arr.take_every( t, 2, 3 ) --> x = { 1, 3, 5 }
---local x = arr.take_every( t, 2, 3, 2 ) --> x = { 2, 4, 6 }
--- ```
---@generic T: any[]
---@param arr T
---@param n integer # Step size.
---@param start? integer # Start index.
---@param count? integer # Max amount of elements to get.
---@return T
function Array.take_every(arr, n, start, count)
checkType('Module:Array.take_every', 1, arr, 'table')
checkType('Module:Array.take_every', 2, n, 'number')
checkType('Module:Array.take_every', 3, start, 'number', true)
checkType('Module:Array.take_every', 4, count, 'number', true)
count = count or #arr
local r = {}
local len = 0
local i = start or 1
while arr[i] ~= nil and len < count do
len = len + 1
r[len] = arr[i]
i = i + n
end
return setmetatable(r, getmetatable(arr))
end
---Return a new table with all duplicates removed.
---@generic T: any[]
---@param arr T
---@param fn? fun(elem: any): any # Function to generate an id for each element. The result will then contain elements that generated unique ids.
---@return T
function Array.unique(arr, fn)
checkType('Module:Array.unique', 1, arr, 'table')
checkType('Module:Array.unique', 2, fn, 'function', true)
fn = fn or function(item) return item end
local r = {}
local len = 0
local hash = {}
local i = 1
while arr[i] ~= nil do
local id = fn(arr[i])
if not hash[id] then
len = len + 1
r[len] = arr[i]
hash[id] = true
end
i = i + 1
end
return setmetatable(r, getmetatable(arr))
end
---Combine elements with the same index from multiple arrays.
---```
---local x = {1, 2, 3}
---local y = {4, 5, 6, 7}
---local z = arr.zip( x, y ) --> z = { { 1, 4 }, { 2, 5 }, { 3, 6 }, { 7 } }
---```
---@param ... any[]
---@return Array
function Array.zip(...)
local arrs = { ... }
checkType('Module:Array.zip', 1, arrs[1], 'table')
local r = {}
local _, longest = Array.max_by(arrs, function(arr) return #arr end)
for i = 1, longest do
local q = {}
for j = 1, #arrs do
table.insert(q, arrs[j][i])
end
table.insert(r, setmetatable(q, Array))
end
return setmetatable(r, Array)
end
-- Range indexing has a performance impact so this is placed in a separate subclass
Array.RI_mt = {}
for k, v in pairs(Array) do
Array.RI_mt[k] = v
end
function Array.RI_mt.__index(t, k)
if type(k) == 'table' then
local res = {}
for i = 1, #k do
res[i] = t[k[i]]
end
return setmetatable(res, Array)
else
return Array[k]
end
end
function Array.RI_mt.__newindex(t, k, v)
if type(k) == 'table' then
if type(v) == 'table' then
for i = 1, #k do
t[k[i]] = v[i]
end
else
for i = 1, #k do
t[k[i]] = v
end
end
else
rawset(t, k, v)
end
end
---Enable range indexing on the input array.
---
---This has a performance impact on reads and writes to the table.
---```
---local t = arr{10, 11, 12, 13, 14, 15}:ri()
---print( t[{2, 3}] ) --> { 11, 12 }
---```
---@param arr any[]
---@param recursive? boolean # Default is false.
---@return Array
function Array.ri(arr, recursive)
checkType('Module:Array.ri', 1, arr, 'table')
checkType('Module:Array.ri', 2, recursive, 'boolean', true)
arr = arr or {}
if recursive then
for _, v in pairs(arr) do
if type(v) == 'table' then
Array.ri(v, true)
end
end
end
if getmetatable(arr) == nil or getmetatable(arr) == Array then
setmetatable(arr, Array.RI_mt)
end
return arr
end
---Globally enable range indexing on all Array objects by default.
---@param set boolean
function Array.allwaysAllowRangeIndexing(set)
checkType('Module:Array.allwaysAllowRangeIndexing', 1, set, 'boolean')
if set then
Array.__index = Array.RI_mt.__index
Array.__newindex = Array.RI_mt.__newindex
else
Array.__index = Array
Array.__newindex = nil
end
end
return Array
c81adb59b4d3a4728952df3ad8d681664333a799
Module:Paramtest
828
57
112
2023-06-24T17:31:26Z
star>Alistair3149
0
Scribunto
text/plain
-- Imported from: https://runescape.wiki/w/Module:Paramtest
--[[
{{Helper module
|name=Paramtest
|fname1 = is_empty(arg)
|ftype1 = String
|fuse1 = Returns true if arg is not defined or contains only whitespace
|fname2 = has_content(arg)
|ftype2 = String
|fuse2 = Returns true if arg exists and does not only contain whitespace
|fname3 = default_to(arg1,arg2)
|ftype3 = String, Any value
|fuse3 = If arg1 exists and does not only contain whitespace, the function returns arg1, otherwise returns arg2
|fname4 = defaults{ {arg1,arg2},...}
|ftype4 = {String, Any value}...
|fuse4 = Does the same as <code>default_to()</code> run over every table passed
|fname5 = table_is_empty(arg)
|ftype5 = Table
|fuse5 = Returns true if the table has no content, it does not check if the content of the table contains anything
|fname6 = table_has_content(arg)
|ftype6 = Table
|fuse6 = returns true if the table has content, it does not check if the content of the table contains anything
}}
--]]
local checkType, checkTypeForNamedArg
do
local _libraryUtil = require("libraryUtil");
checkType = _libraryUtil.checkType;
checkTypeForNamedArg = _libraryUtil.checkTypeForNamedArg;
end
--
-- Tests basic properties of parameters
--
local p = {}
--
-- Tests if the parameter is empty, all white space, or undefined
--
function p.is_empty(arg)
return not string.find(arg or '', '%S')
end
--
-- Tests if the table parameter is empty
--
function p.table_is_empty(arg)
for _, _ in pairs(arg) do
return false
end
return true
end
--
-- Returns the parameter if it has any content, the default (2nd param)
--
function p.default_to(arg, default)
if string.find(arg or '', '%S') then
return arg
else
return default
end
end
--
-- Returns a list of paramaters if it has any content, or the default
--
function p.defaults(args)
checkType("defaults", 1, args, "table");
local ret = {}
for i, v in ipairs(args) do
checkTypeForNamedArg("defaults", i, v, "table");
ret[i] = p.default_to(v[1], v[2]);
end
return unpack(ret, 1, #args);
end
--
-- Tests if the parameter has content
-- The same as !is_empty, but this is more readily clear
--
function p.has_content(arg)
return string.find(arg or '', '%S')
end
--
-- Tests if the table parameter has content
-- The same as !table_is_empty, but this is more readily clear
--
function p.table_has_content(arg)
for _, _ in pairs(arg) do
return true
end
return false
end
--
-- uppercases first letter
--
function p.ucfirst(arg)
if not arg or arg:len() == 0 then
return nil
elseif arg:len() == 1 then
return arg:upper()
else
return arg:sub(1,1):upper() .. arg:sub(2)
end
end
--
-- uppercases first letter, lowercases everything else
--
function p.ucflc(arg)
if not arg or arg:len() == 0 then
return nil
elseif arg:len() == 1 then
return arg:upper()
else
return arg:sub(1,1):upper() .. arg:sub(2):lower()
end
end
return p
d69422a8379e1fcb190fe16e6d212071b9caa1dc
Module:Hatnote
828
41
80
2023-07-11T03:30:11Z
Star>Alistair3149
0
Sync with upstream
Scribunto
text/plain
--------------------------------------------------------------------------------
-- Module:Hatnote --
-- --
-- This module produces hatnote links and links to related articles. It --
-- implements the {{hatnote}} and {{format link}} meta-templates and includes --
-- helper functions for other Lua hatnote modules. --
--------------------------------------------------------------------------------
local libraryUtil = require('libraryUtil')
local checkType = libraryUtil.checkType
local mArguments -- lazily initialise [[Module:Arguments]]
local yesno -- lazily initialise [[Module:Yesno]]
local p = {}
--------------------------------------------------------------------------------
-- Helper functions
--------------------------------------------------------------------------------
local function getArgs(frame)
-- Fetches the arguments from the parent frame. Whitespace is trimmed and
-- blanks are removed.
mArguments = require('Module:Arguments')
return mArguments.getArgs(frame, {parentOnly = true})
end
local function removeInitialColon(s)
-- Removes the initial colon from a string, if present.
return s:match('^:?(.*)')
end
function p.defaultClasses(inline)
-- Provides the default hatnote classes as a space-separated string; useful
-- for hatnote-manipulation modules like [[Module:Hatnote group]].
return
(inline == 1 and 'hatnote-inline' or 'hatnote') .. ' ' ..
'navigation-not-searchable'
end
function p.disambiguate(page, disambiguator)
-- Formats a page title with a disambiguation parenthetical,
-- i.e. "Example" → "Example (disambiguation)".
checkType('disambiguate', 1, page, 'string')
checkType('disambiguate', 2, disambiguator, 'string', true)
disambiguator = disambiguator or 'disambiguation'
return mw.ustring.format('%s (%s)', page, disambiguator)
end
function p.findNamespaceId(link, removeColon)
-- Finds the namespace id (namespace number) of a link or a pagename. This
-- function will not work if the link is enclosed in double brackets. Colons
-- are trimmed from the start of the link by default. To skip colon
-- trimming, set the removeColon parameter to false.
checkType('findNamespaceId', 1, link, 'string')
checkType('findNamespaceId', 2, removeColon, 'boolean', true)
if removeColon ~= false then
link = removeInitialColon(link)
end
local namespace = link:match('^(.-):')
if namespace then
local nsTable = mw.site.namespaces[namespace]
if nsTable then
return nsTable.id
end
end
return 0
end
function p.makeWikitextError(msg, helpLink, addTrackingCategory, title)
-- Formats an error message to be returned to wikitext. If
-- addTrackingCategory is not false after being returned from
-- [[Module:Yesno]], and if we are not on a talk page, a tracking category
-- is added.
checkType('makeWikitextError', 1, msg, 'string')
checkType('makeWikitextError', 2, helpLink, 'string', true)
yesno = require('Module:Yesno')
title = title or mw.title.getCurrentTitle()
-- Make the help link text.
local helpText
if helpLink then
helpText = ' ([[' .. helpLink .. '|help]])'
else
helpText = ''
end
-- Make the category text.
local category
if not title.isTalkPage -- Don't categorise talk pages
and title.namespace ~= 2 -- Don't categorise userspace
and yesno(addTrackingCategory) ~= false -- Allow opting out
then
category = 'Hatnote templates with errors'
category = mw.ustring.format(
'[[%s:%s]]',
mw.site.namespaces[14].name,
category
)
else
category = ''
end
return mw.ustring.format(
'<strong class="error">Error: %s%s.</strong>%s',
msg,
helpText,
category
)
end
local curNs = mw.title.getCurrentTitle().namespace
p.missingTargetCat =
--Default missing target category, exported for use in related modules
((curNs == 0) or (curNs == 14)) and
'Articles with hatnote templates targeting a nonexistent page' or nil
function p.quote(title)
--Wraps titles in quotation marks. If the title starts/ends with a quotation
--mark, kerns that side as with {{-'}}
local quotationMarks = {
["'"]=true, ['"']=true, ['“']=true, ["‘"]=true, ['”']=true, ["’"]=true
}
local quoteLeft, quoteRight = -- Test if start/end are quotation marks
quotationMarks[string.sub(title, 1, 1)],
quotationMarks[string.sub(title, -1, -1)]
if quoteLeft or quoteRight then
title = mw.html.create("span"):wikitext(title)
end
if quoteLeft then title:css("padding-left", "0.15em") end
if quoteRight then title:css("padding-right", "0.15em") end
return '"' .. tostring(title) .. '"'
end
--------------------------------------------------------------------------------
-- Hatnote
--
-- Produces standard hatnote text. Implements the {{hatnote}} template.
--------------------------------------------------------------------------------
local function decorateHatnote(hatnote, options)
local function getIcon(filename)
local html = ''
if type(filename) == 'string' then
local icon = mw.html.create('span')
icon
:addClass('hatnote-icon')
:addClass('metadata')
:wikitext('[[File:' .. filename .. '|14px|link=]]')
:done()
html = tostring(icon)
end
return html
end
local container = mw.html.create('div')
container
:addClass('hatnote-container')
:wikitext(getIcon(options.icon))
:wikitext(tostring(hatnote))
:done()
return container
end
function p.hatnote(frame)
local args = getArgs(frame)
local s = args[1]
if not s then
return p.makeWikitextError(
'no text specified',
'Template:Hatnote#Errors',
args.category
)
end
return p._hatnote(s, {
extraclasses = args.extraclasses,
selfref = args.selfref
})
end
function p._hatnote(s, options)
checkType('_hatnote', 1, s, 'string')
checkType('_hatnote', 2, options, 'table', true)
options = options or {}
local inline = options.inline
local hatnote = mw.html.create(inline == 1 and 'span' or 'div')
local extraclasses
if type(options.extraclasses) == 'string' then
extraclasses = options.extraclasses
end
hatnote
:attr('role', 'note')
:addClass(p.defaultClasses(inline))
:addClass(extraclasses)
:addClass(options.selfref and 'selfref' or nil)
:wikitext(s)
-- Decorate WP hatnote to SCW standard
hatnote = decorateHatnote(hatnote, options)
return mw.getCurrentFrame():extensionTag{
name = 'templatestyles', args = { src = 'Module:Hatnote/styles.css' }
} .. tostring(hatnote)
end
return p
7e322cb6950c0f36959bceccc679cc8f52959f7c
Module:DependencyList
828
55
108
2023-07-13T23:58:12Z
star>Alistair3149
0
Scribunto
text/plain
require("strict");
local p = {}
local libraryUtil = require( 'libraryUtil' )
local arr = require( 'Module:Array' )
local yn = require( 'Module:Yesno' )
local param = require( 'Module:Paramtest' )
local dpl = require( 'Module:DPLlua' )
local userError = require("Module:User error")
local mHatnote = require('Module:Hatnote')
local mHatlist = require('Module:Hatnote list')
local moduleIsUsed = false
local COLLAPSE_LIST_LENGTH_THRESHOLD = 1
local MAX_DYNAMIC_REQUIRE_LIST_LENGTH = 30
local dynamicRequireListQueryCache = {}
local builtins = {
--[[
["libraryUtil"] = {
link = "mw:Special:MyLanguage/Extension:Scribunto/Lua reference manual#libraryUtil",
categories = {},
}
]]
["strict"] = {
link = "mw:Special:MyLanguage/Extension:Scribunto/Lua reference manual#strict",
categories = { "Strict mode modules" },
},
};
--- Used in case 'require( varName )' is found. Attempts to find a string value stored in 'varName'.
---@param content string The content of the module to search in
---@param varName string
---@return string
local function substVarValue( content, varName )
local res = content:match( varName .. '%s*=%s*(%b""%s-%.*)' ) or content:match( varName .. "%s*=%s*(%b''%s-%.*)" ) or ''
if res:find( '^(["\'])[Mm]odule:[%S]+%1' ) and not res:find( '%.%.' ) and not res:find( '%%%a' ) then
return mw.text.trim( res )
else
return ''
end
end
---@param capture string
---@param content string The content of the module to search in
---@return string
local function extractModuleName( capture, content )
capture = capture:gsub( '^%(%s*(.-)%s*%)$', '%1' )
if capture:find( '^(["\']).-%1$' ) then -- Check if it is already a pure string
return capture
elseif capture:find( '^[%a_][%w_]*$' ) then -- Check if if is a single variable
return substVarValue( content, capture )
end
return capture
end
---@param str string
---@return string
local function formatPageName( str )
local name = mw.text.trim(str)
:gsub( '^([\'\"])(.-)%1$', function(_, x) return x end ) -- Only remove quotes at start and end of string if both are the same type
:gsub( '_', ' ' )
:gsub( '^.', string.upper )
:gsub( ':.', string.upper )
return name
end
---@param str string
---@return string
local function formatModuleName( str, allowBuiltins )
if allowBuiltins then
local name = mw.text.trim(str)
-- Only remove quotes at start and end of string if both are the same type
:gsub([[^(['"])(.-)%1$]], function(_, x) return x end);
local builtin = builtins[name];
if builtin then
return builtin.link .. "|" .. name, builtin;
end
end
local module = formatPageName( str )
if not string.find( module, '^[Mm]odule:' ) then
module = 'Module:' .. module
end
return module
end
local function dualGmatch( str, pat1, pat2 )
local f1 = string.gmatch( str, pat1 )
local f2 = string.gmatch( str, pat2 )
return function()
return f1() or f2()
end
end
--- Used in case a construct like 'require( "Module:wowee/" .. isTheBest )' is found.
--- Will return a list of pages which satisfy this pattern where 'isTheBest' can take any value.
---@param query string
---@return string[] Sequence of strings
local function getDynamicRequireList( query )
local isDynamic = true;
if query:find( '%.%.' ) then
query = mw.text.split( query, '..', true )
query = arr.map( query, function(x) return mw.text.trim(x) end )
query = arr.map( query, function(x) return (x:match('^[\'\"](.-)[\'\"]$') or '%') end )
query = table.concat( query )
else
local _; _, query = query:match( '(["\'])(.-)%1' )
if query == nil then
return {}, isDynamic
end
local replacements;
query, replacements = query:gsub( '%%%a', '%%' )
if replacements == 0 then
isDynamic = false;
end
end
query = query:gsub( '^[Mm]odule:', '' )
if query:find( '^[Dd]ata/' ) then
return { 'Module:' .. query }, isDynamic; -- This format will later be used by formatDynamicQueryLink()
end
if dynamicRequireListQueryCache[ query ] then
return dynamicRequireListQueryCache[ query ], isDynamic;
end
local list = dpl.ask{
namespace = 'Module',
titlematch = query,
nottitlematch = '%/doc|'..query..'/%',
distinct = 'strict',
ignorecase = true,
ordermethod = 'title',
count = MAX_DYNAMIC_REQUIRE_LIST_LENGTH + 1,
skipthispage = 'no',
allowcachedresults = true,
cacheperiod = 604800 -- One week
}
if #list > MAX_DYNAMIC_REQUIRE_LIST_LENGTH then
list = { 'Module:' .. query }
end
dynamicRequireListQueryCache[ query ] = list
return list, isDynamic;
end
--- Returns a list of modules loaded and required by module 'moduleName'.
---@param moduleName string
---@param searchForUsedTemplates boolean
---@return string[], string[], string[], string[]
local function getRequireList( moduleName, searchForUsedTemplates )
local content = mw.title.new( moduleName ):getContent()
local requireList = arr{}
local loadDataList = arr{}
local usedTemplateList = arr{}
local dynamicRequirelist = arr{}
local dynamicLoadDataList = arr{}
local extraCategories = arr{}
assert( content ~= nil, string.format( '%s does not exist', moduleName ) )
content = content:gsub( '%-%-%[(=-)%[.-%]%1%]', '' ):gsub( '%-%-[^\n]*', '' ) -- Strip comments
for match in dualGmatch( content, 'require%s*(%b())', 'require%s*((["\'])%s*[Mm]odule:.-%2)' ) do
match = mw.text.trim( match )
match = extractModuleName( match, content )
if match:find( '%.%.' ) or match:find( '%%%a' ) then
for _, x in ipairs( getDynamicRequireList( match ) ) do
table.insert( dynamicRequirelist, x )
end
elseif match ~= '' then
local builtin;
match, builtin = formatModuleName( match, true )
table.insert( requireList, match )
if builtin then
local builtinCategories = builtin.categories;
if type(builtinCategories) == "table" then
for _, x in ipairs(builtinCategories) do
table.insert(extraCategories, x);
end
end
end
end
end
for match in dualGmatch( content, 'mw%.loadData%s*(%b())', 'mw%.loadData%s*((["\'])%s*[Mm]odule:.-%2)' ) do
match = mw.text.trim( match )
match = extractModuleName( match, content )
if match:find( '%.%.' ) or match:find( '%%%a' ) then
for _, x in ipairs( getDynamicRequireList( match ) ) do
table.insert( dynamicLoadDataList, x )
end
elseif match ~= '' then
match = formatModuleName( match, true )
table.insert( loadDataList, match )
end
end
for match in dualGmatch( content, 'mw%.loadJsonData%s*(%b())', 'mw%.loadJsonData%s*((["\'])%s*[Mm]odule:.-%2)' ) do
match = mw.text.trim( match )
match = extractModuleName( match, content )
if match:find( '%.%.' ) or match:find( '%%%a' ) then
for _, x in ipairs( getDynamicRequireList( match ) ) do
table.insert( dynamicLoadDataList, x )
end
elseif match ~= '' then
match = formatModuleName( match, true )
table.insert( loadDataList, match )
end
end
for func, match in string.gmatch( content, 'pcall%s*%(([^,]+),([^%),]+)' ) do
func = mw.text.trim( func )
match = mw.text.trim( match )
local dynList, isDynamic;
if func == 'require' then
dynList, isDynamic = getDynamicRequireList(match);
if (isDynamic == false and #dynList == 1) then
table.insert(requireList, dynList[1]);
else for _, x in ipairs(dynList) do
table.insert( dynamicRequirelist, x )
end end
elseif func == 'mw.loadData' then
dynList, isDynamic = getDynamicRequireList(match);
if (isDynamic == false and #dynList == 1) then
table.insert(loadDataList, dynList[1]);
else for _, x in ipairs(dynList) do
table.insert( dynamicLoadDataList, x )
end end
end
end
if searchForUsedTemplates then
for preprocess in string.gmatch( content, ':preprocess%s*(%b())' ) do
local function recursiveGMatch( str, pat )
local list = {}
local i = 0
repeat
for match in string.gmatch( list[i] or str, pat ) do
table.insert( list, match )
end
i = i + 1
until i > #list or i > 100
i = 0
return function()
i = i + 1
return list[i]
end
end
for template in recursiveGMatch( preprocess, '{(%b{})}' ) do
local name = string.match( template, '{(.-)[|{}]' )
if name ~= '' then
if name:find( ':' ) then
local ns = name:match( '^(.-):' )
if arr.contains( {'', 'template', 'user'}, ns:lower() ) then
table.insert( usedTemplateList, name )
elseif ns == ns:upper() then
table.insert( usedTemplateList, ns ) -- Probably a magic word
end
else
if name:match( '^%u+$' ) or name == '!' then
table.insert( usedTemplateList, name ) -- Probably a magic word
else
table.insert( usedTemplateList, 'Template:'..name )
end
end
end
end
end
end
requireList = requireList .. dynamicRequirelist:reject( loadDataList )
requireList = requireList:unique()
loadDataList = loadDataList .. dynamicLoadDataList:reject( requireList )
loadDataList = loadDataList:unique()
usedTemplateList = usedTemplateList:unique()
extraCategories = extraCategories:unique()
table.sort( requireList )
table.sort( loadDataList )
table.sort( usedTemplateList )
table.sort( extraCategories )
return requireList, loadDataList, usedTemplateList, extraCategories
end
--- Returns a list with module and function names used in all '{{#Invoke:moduleName|funcName}}' found on page 'templateName'.
---@param templateName string
---@return table<string, string>[]
local function getInvokeCallList( templateName )
local content = mw.title.new( templateName ):getContent()
local invokeList = {}
assert( content ~= nil, string.format( '%s does not exist', templateName ) )
for moduleName, funcName in string.gmatch( content, '{{[{|safeubt:}]-#[Ii]nvoke:([^|]+)|([^}|]+)[^}]*}}' ) do
moduleName = formatModuleName( moduleName )
funcName = mw.text.trim( funcName )
if string.find( funcName, '^{{{' ) then
funcName = funcName .. '}}}'
end
table.insert( invokeList, {moduleName=moduleName, funcName=funcName} )
end
invokeList = arr.unique( invokeList, function(x) return x.moduleName..x.funcName end )
table.sort( invokeList, function(x, y) return x.moduleName..x.funcName < y.moduleName..y.funcName end )
return invokeList
end
---@param pageName string
---@param addCategories boolean
---@return string
local function messageBoxUnused( pageName, addCategories )
local mbox = require( 'Module:Mbox' )._mbox
local category = addCategories and '[[Category:Unused modules]]' or ''
return mbox(
'This module is unused.',
string.format( 'This module is neither invoked by a template nor required/loaded by another module. If this is in error, make sure to add <code>{{[[Template:Documentation|Documentation]]}}</code>/<code>{{[[Template:No documentation|No documentation]]}}</code> to the calling template\'s or parent\'s module documentation.',
pageName
),
{ icon = 'WikimediaUI-Alert.svg' }
) .. category
end
local function collapseList( list, id, listType )
local text = string.format( '%d %s', #list, listType )
local button = '<span>' .. text .. ':</span> '
local content = mHatlist.andList( list, false )
return { tostring( button ) .. tostring( content ) }
end
--- Creates a link to [[Special:Search]] showing all pages found by getDynamicRequireList() in case it found more than MAX_DYNAMIC_REQUIRE_LIST_LENGTH pages.
---@param query string @This will be in a format like 'Module:Wowee/%' or 'Module:Wowee/%/data'
---@return string
local function formatDynamicQueryLink( query )
local prefix = query:match( '^([^/]+)' )
local linkText = query:gsub( '%%', '< ... >' )
query = query:gsub( '^Module:', '' )
query = query:gsub( '([^/]+)/?', function ( match )
if match == '%' then
return '\\/[^\\/]+'
else
return '\\/"' .. match .. '"'
end
end )
query = query:gsub( '^\\/', '' )
query = string.format(
'intitle:/%s%s/i -intitle:/%s\\/""/i -intitle:doc prefix:"%s"',
query,
query:find( '"$' ) and '' or '""',
query,
prefix
)
return string.format( '<span class="plainlinks">[%s %s]</span>', tostring( mw.uri.fullUrl( 'Special:Search', { search = query } ) ), linkText )
end
---@param templateName string
---@param addCategories boolean
---@param invokeList table<string, string>[] @This is the list returned by getInvokeCallList()
---@return string
local function formatInvokeCallList( templateName, addCategories, invokeList )
local category = addCategories and '[[Category:Lua-based templates]]' or ''
local res = {}
for _, item in ipairs( invokeList ) do
local msg = string.format(
"'''%s''' invokes function '''%s''' in [[%s]] using [[Star Citizen:Lua|Lua]].",
templateName,
item.funcName,
item.moduleName
)
table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) )
end
if #invokeList > 0 then
table.insert( res, category )
end
return table.concat( res )
end
---@param moduleName string
---@param addCategories boolean
---@param whatLinksHere string @A list generated by a dpl of pages in the Template namespace which link to moduleName.
---@return string
local function formatInvokedByList( moduleName, addCategories, whatLinksHere )
local function lcfirst( str )
return string.gsub( str, '^[Mm]odule:.', string.lower )
end
local templateData = arr.map( whatLinksHere, function(x) return {templateName=x, invokeList=getInvokeCallList(x)} end )
templateData = arr.filter( templateData, function(x)
return arr.any( x.invokeList, function(y)
return lcfirst(y.moduleName) == lcfirst(moduleName)
end )
end )
local invokedByList = {}
for _, template in ipairs( templateData ) do
for _, invoke in ipairs( template.invokeList ) do
table.insert( invokedByList, string.format( "function '''%s''' is invoked by [[%s]]", invoke.funcName, template.templateName ) )
end
end
table.sort( invokedByList)
local res = {}
if #invokedByList > COLLAPSE_LIST_LENGTH_THRESHOLD then
local msg = string.format(
"'''%s''' is invoked by %s.",
moduleName,
collapseList( invokedByList, 'invokedBy', 'templates' )[1]
)
table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) )
else
for _, item in ipairs( invokedByList ) do
local msg = string.format(
"'''%s's''' %s.",
moduleName,
item
)
table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) )
end
end
if #templateData > 0 then
moduleIsUsed = true
table.insert( res, (addCategories and '[[Category:Template invoked modules]]' or '') )
end
return table.concat( res )
end
---@param moduleName string
---@param addCategories boolean
---@param whatLinksHere string @A list generated by a dpl of pages in the Module namespace which link to moduleName.
---@return string
local function formatRequiredByList( moduleName, addCategories, whatLinksHere )
local childModuleData = arr.map( whatLinksHere, function ( title )
local requireList, loadDataList = getRequireList( title )
return {name=title, requireList=requireList, loadDataList=loadDataList}
end )
local requiredByList = arr.map( childModuleData, function ( item )
if arr.any( item.requireList, function(x) return x:lower()==moduleName:lower() end ) then
if item.name:find( '%%' ) then
return formatDynamicQueryLink( item.name )
else
return '[[' .. item.name .. ']]'
end
end
end )
local loadedByList = arr.map( childModuleData, function ( item )
if arr.any( item.loadDataList, function(x) return x:lower()==moduleName:lower() end ) then
if item.name:find( '%%' ) then
return formatDynamicQueryLink( item.name )
else
return '[[' .. item.name .. ']]'
end
end
end )
if #requiredByList > 0 or #loadedByList > 0 then
moduleIsUsed = true
end
if #requiredByList > COLLAPSE_LIST_LENGTH_THRESHOLD then
requiredByList = collapseList( requiredByList, 'requiredBy', 'modules' )
end
if #loadedByList > COLLAPSE_LIST_LENGTH_THRESHOLD then
loadedByList = collapseList( loadedByList, 'loadedBy', 'modules' )
end
local res = {}
for _, requiredByModuleName in ipairs( requiredByList ) do
local msg = string.format(
"'''%s''' is required by %s.",
moduleName,
requiredByModuleName
)
table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) )
end
if #requiredByList > 0 then
table.insert( res, (addCategories and '[[Category:Modules required by modules]]' or '') )
end
for _, loadedByModuleName in ipairs( loadedByList ) do
local msg = string.format(
"'''%s''' is loaded by %s.",
moduleName,
requiredByModuleName
)
table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) )
end
if #loadedByList > 0 then
table.insert( res, (addCategories and '[[Category:Module data]]' or '') )
end
return table.concat( res )
end
local function formatRequireList( currentPageName, addCategories, requireList )
local res = {}
if #requireList > COLLAPSE_LIST_LENGTH_THRESHOLD then
requireList = collapseList( requireList, 'require', 'modules' )
end
for _, requiredModuleName in ipairs( requireList ) do
local msg = string.format(
"'''%s''' requires %s.",
currentPageName,
requiredModuleName
)
table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) )
end
if #requireList > 0 then
table.insert( res, (addCategories and '[[Category:Modules requiring modules]]' or '') )
end
return table.concat( res )
end
local function formatLoadDataList( currentPageName, addCategories, loadDataList )
local res = {}
if #loadDataList > COLLAPSE_LIST_LENGTH_THRESHOLD then
loadDataList = collapseList( loadDataList, 'loadData', 'modules' )
end
for _, loadedModuleName in ipairs( loadDataList ) do
local msg = string.format(
"'''%s''' loads data from %s.",
currentPageName,
loadedModuleName
)
table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) )
end
if #loadDataList > 0 then
table.insert( res, (addCategories and '[[Category:Modules using data]]' or '') )
end
return table.concat( res )
end
local function formatUsedTemplatesList( currentPageName, addCategories, usedTemplateList )
local res = {}
if #usedTemplateList > COLLAPSE_LIST_LENGTH_THRESHOLD then
usedTemplateList = collapseList( usedTemplateList, 'usedTemplates', 'templates' )
end
for _, templateName in ipairs( usedTemplateList ) do
local msg = string.format(
"'''%s''' transcludes [[%s]] using <samp>frame:preprocess()</samp>.",
currentPageName,
templateName
)
table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) )
end
return table.concat( res )
end
function p.main( frame )
local args = frame:getParent().args
return p._main( args[1], args.category, args.isUsed )
end
---@param currentPageName string|nil
---@param addCategories boolean|string|nil
---@return string
function p._main( currentPageName, addCategories, isUsed )
libraryUtil.checkType( 'Module:RequireList._main', 1, currentPageName, 'string', true )
libraryUtil.checkTypeMulti( 'Module:RequireList._main', 2, addCategories, {'boolean', 'string', 'nil'} )
libraryUtil.checkTypeMulti( 'Module:RequireList._main', 3, isUsed, {'boolean', 'string', 'nil'} )
local title = mw.title.getCurrentTitle()
-- Leave early if not in module or template namespace
if param.is_empty( currentPageName ) and
( not arr.contains( {'Module', 'Template'}, title.nsText ) ) then
return ''
end
currentPageName = param.default_to( currentPageName, title.fullText )
currentPageName = string.gsub( currentPageName, '/[Dd]oc$', '' )
currentPageName = formatPageName( currentPageName )
addCategories = yn( param.default_to( addCategories, title.subpageText~='doc' ) )
moduleIsUsed = yn( param.default_to( isUsed, false ) )
if title.text:lower():find( 'sandbox' ) then
moduleIsUsed = true -- Don't show sandbox modules as unused
end
if currentPageName:find( '^Template:' ) then
local ok, invokeList = pcall( getInvokeCallList, currentPageName )
if ok then
return formatInvokeCallList( currentPageName, addCategories, invokeList )
else
return userError(invokeList)
end
end
local whatTemplatesLinkHere, whatModulesLinkHere = dpl.ask( {
namespace = 'Template',
linksto = currentPageName,
distinct = 'strict',
ignorecase = true,
ordermethod = 'title',
allowcachedresults = true,
cacheperiod = 604800 -- One week
}, {
namespace = 'Module',
linksto = currentPageName,
nottitlematch = '%/doc%|' .. currentPageName:gsub( 'Module:', '' ),
distinct = 'strict',
ignorecase = true,
ordermethod = 'title',
allowcachedresults = true,
cacheperiod = 604800 -- One week
} )
local requireList, loadDataList, usedTemplateList, extraCategories;
do
local ok;
ok, requireList, loadDataList, usedTemplateList, extraCategories = pcall(getRequireList, currentPageName, true);
if not ok then
return userError(requireList);
end
end
requireList = arr.map( requireList, function ( moduleName )
if moduleName:find( '%%' ) then
return formatDynamicQueryLink( moduleName )
else
return '[[' .. moduleName .. ']]'
end
end )
loadDataList = arr.map( loadDataList, function ( moduleName )
if moduleName:find( '%%' ) then
return formatDynamicQueryLink( moduleName )
else
return '[[' .. moduleName .. ']]'
end
end )
usedTemplateList = arr.map( usedTemplateList, function( templateName )
if string.find( templateName, ':' ) then -- Real templates are prefixed by a namespace, magic words are not
return '[['..templateName..']]'
else
return "'''{{"..templateName.."}}'''" -- Magic words don't have a page so make them bold instead
end
end )
local res = {}
table.insert( res, formatInvokedByList( currentPageName, addCategories, whatTemplatesLinkHere ) )
table.insert( res, formatRequireList( currentPageName, addCategories, requireList ) )
table.insert( res, formatLoadDataList( currentPageName, addCategories, loadDataList ) )
table.insert( res, formatUsedTemplatesList( currentPageName, addCategories, usedTemplateList ) )
table.insert( res, formatRequiredByList( currentPageName, addCategories, whatModulesLinkHere ) )
if addCategories then
extraCategories = arr.map(extraCategories, function(categoryName)
return "[[Category:" .. categoryName .. "]]";
end);
table.insert(res, table.concat(extraCategories));
end
if not moduleIsUsed then
table.insert( res, 1, messageBoxUnused( currentPageName:gsub( 'Module:', '' ), addCategories ) )
end
return table.concat( res )
end
return p
-- </nowiki>
d5f03ab1075172cdbb69e217ef5ed86f0d973480
Module:Infobox/styles.css
828
64
126
2023-07-15T08:05:29Z
star>Alistair3149
0
text
text/plain
.infobox {
/* In case if tooltips go out of boundary */
overflow: visible;
width: 100%;
max-width: 400px;
margin-top: 0;
margin-bottom: var( --space-md );
background: var( --color-surface-2 );
border-radius: var( --border-radius--medium );
border-spacing: 0;
font-size: 0.875rem;
text-align: left;
display: block;
}
/* Table elements */
.infobox tbody {
display: flex;
flex-wrap: wrap;
}
.infobox tr {
display: flex;
box-sizing: border-box;
flex-direction: column;
padding: 0 10px;
margin-top: 10px;
}
.infobox th,
.infobox td {
padding: 0 5px;
}
/* Infobox column */
.infobox .infobox-nocol {
width: 100%;
flex-direction: row;
}
.infobox .infobox-nocol th {
width: 30%;
}
.infobox .infobox-nocol td {
width: 70%;
}
.infobox .infobox-col1 {
width: 100%;
}
.infobox .infobox-col2 {
width: 50%;
}
.infobox .infobox-col3 {
width: calc( 100% / 3 );
}
.infobox .infobox-col4 {
width: 25%;
}
.infobox-data {
min-width: 25%;
}
/* Infobox image */
.infobox .infobox-image {
overflow: hidden;
padding: 0;
margin-top: 0;
border-radius: var( --border-radius--medium ) var( --border-radius--medium ) 0 0;
}
.infobox-image td {
padding: 0;
}
.infobox-image--light .image {
background: #eaecf0;
}
.infobox-image--dark .image {
background: #2b2f36;
}
.infobox-image .image:hover img {
transform: scale( 1.1 );
}
.infobox-image img {
display: block;
max-width: 100%;
background: var( --background-color-quiet--hover );
}
/* Neutral background for all transprent SVG */
.infobox-image img[ src$='.svg' ] {
background: #eaecf0;
}
/* Infobox title */
.infobox .infobox-title {
width: 100%;
margin-top: 20px;
margin-bottom: 5px;
color: var( --color-base--emphasized );
font-size: var( --font-size-h3 );
line-height: var( --line-height-xs );
}
/* Infobox indicator */
.infobox .infobox-indicator {
margin-top: 0;
padding: 0;
}
/* Infobox subtitle */
.infobox .infobox-subtitle {
/* Cancel infobox-title bottom margin */
margin-top: -5px;
margin-bottom: 5px;
}
.infobox .infobox-indicator th,
.infobox .infobox-subtitle th {
display: none;
}
/* Infobox header */
.infobox .infobox-header {
width: 100%;
padding-top: 15px;
border-top: 1px solid;
border-color: var( --border-color-base );
margin-top: 15px;
color: var( --color-base--emphasized );
line-height: var( --line-height-xs );
font-size: 1rem;
}
/* Infobox value */
.infobox-data th {
color: var( --color-base--subtle );
font-size: 0.8125rem;
font-weight: normal;
letter-spacing: 0.75px;
}
.infobox-data td {
font-weight: 600;
}
.infobox-data ul,
.infobox-data ol {
margin-top: 0;
}
/* Infobox button */
.infobox .infobox-button-bar {
width: 100%;
padding: 0;
margin-top: 25px;
text-align: center;
}
.infobox-button-bar th {
padding: 0;
}
/* Collapsible toggle */
.infobox tr:first-of-type .mw-collapsible-toggle {
position: relative;
display: none;
float: none;
}
.infobox tr:first-of-type .mw-collapsible-toggle .mw-collapsible-text {
position: absolute;
right: 0;
display: block;
padding: 5px 15px;
background: var( --color-destructive );
border-radius: 0 var( --border-radius--medium );
color: #fff;
}
.infobox tr:first-of-type .mw-collapsible-toggle .mw-collapsible-text:hover {
background: var( --color-destructive--hover );
}
.infobox tr:first-of-type .mw-collapsible-toggle .mw-collapsible-text:active {
background: var( --color-destructive--active );
}
.infobox tr:first-of-type .mw-collapsible-toggle-collapsed .mw-collapsible-text {
background: var( --color-primary );
}
.infobox tr:first-of-type .mw-collapsible-toggle-collapsed .mw-collapsible-text:hover {
background: var( --color-primary--hover );
}
.infobox tr:first-of-type .mw-collapsible-toggle-collapsed .mw-collapsible-text:active {
background: var( --color-primary--active );
}
.infobox tr:first-of-type .mw-collapsible-toggle:before,
.infobox tr:first-of-type .mw-collapsible-toggle:after {
content: none;
}
@media only screen and ( max-width: 720px ) {
.infobox {
margin-right: auto;
margin-left: auto;
}
.infobox tr:first-of-type .mw-collapsible-toggle {
display: block;
}
}
754ac9608eeaef9b15784d251643ea8c0a01b58e
Module:Documentation
828
56
110
2023-11-10T05:31:21Z
star>Alistair3149
0
Undo revision 230589 by [[Special:Contributions/Alistair3149|Alistair3149]] ([[User talk:Alistair3149|talk]])
Scribunto
text/plain
-- <nowiki>
local dependencyList = require( 'Module:DependencyList' )
local yn = require( 'Module:Yesno' )
local hatnote = require( 'Module:Hatnote' )._hatnote
local mbox = require( 'Module:Mbox' )._mbox
local lang = mw.getContentLanguage()
local p = {}
function p.doc( frame )
local title = mw.title.getCurrentTitle()
local args = frame:getParent().args
local page = args[1] or mw.ustring.gsub( title.fullText, '/doc$', '' )
local ret, cats, ret1, ret2, ret3
local pageType = title.namespace == 828 and 'module' or 'template'
local opts = frame.args;
-- subpage header
if title.subpageText == 'doc' then
ret = mbox(
'This is a documentation subpage for ' .. page .. '.',
string.format(
'It contains usage information, categories, and other content that is not part of the [[' .. page .. '|original %s page]].',
pageType
),
{ icon = 'WikimediaUI-Notice.svg' }
)
if title.namespace == 10 then -- Template namespace
cats = '[[Category:Template documentation|' .. title.baseText .. ']]'
ret2 = dependencyList._main()
elseif title.namespace == 828 then -- Module namespace
cats = '[[Category:Module documentation|' .. title.baseText .. ']]'
ret2 = dependencyList._main()
ret2 = ret2 .. require('Module:Module toc').main()
else
cats = ''
ret2 = ''
end
return tostring( ret ) .. ret2 .. cats
end
-- template header
-- don't use mw.html as we aren't closing the main div tag
ret1 = '<div class="documentation">'
ret2 = mw.html.create( nil )
:tag( 'div' )
:addClass( 'documentation-header' )
:tag( 'span' )
:addClass( 'documentation-title' )
:wikitext( lang:ucfirst( string.format('%s documentation', pageType) ) )
:done()
:tag( 'span' )
:addClass( 'documentation-links plainlinks' )
:wikitext(
'[[' .. tostring( mw.uri.fullUrl( page .. '/doc', {action='view'} ) ) .. ' view]]' ..
'[[' .. tostring( mw.uri.fullUrl( page .. '/doc', {action='edit'} ) ) .. ' edit]]' ..
'[[' .. tostring( mw.uri.fullUrl( page .. '/doc', {action='history'} ) ) .. ' history]]' ..
'[<span class="jsPurgeLink">[' .. tostring( mw.uri.fullUrl( title.fullText, {action='purge'} ) ) .. ' purge]</span>]'
)
:done()
:done()
:tag( 'div' )
:addClass( 'documentation-subheader' )
:tag( 'span' )
:addClass( 'documentation-documentation' )
:wikitext( 'This documentation is transcluded from [[' .. page .. '/doc]]. Changes can be proposed in the talk page.' )
:done()
:wikitext(frame:extensionTag{ name = 'templatestyles', args = { src = 'Documentation/styles.css'} })
:done()
ret3 = {}
if args.scwShared then
--- Message box
table.insert( ret3,
mbox(
string.format(
"'''%s''' is [%s%s shared across] the Star Citizen Wikis.",
title.fullText,
'https://github.com/The-Star-Citizen-Wikis/SharedModules/tree/master/',
mw.uri.encode( title.rootText, 'PATH' )
),
string.format(
'This %s is shared across the Star Citizen Wikis. Any changes should also be relayed to the GitHub repository.',
pageType
),
{ icon = 'WikimediaUI-ArticleDisambiguation-ltr.svg' }
)
)
--- Set category
table.insert( ret3, string.format( '[[Category:%s shared by the Star Citizen Wikis]]', lang:ucfirst( pageType ) .. 's' ) )
--- Interlanguage link
--- TODO: Make this into a for loop when there are more wikis
table.insert( ret3, string.format( '[[%s:%s]]', 'de', title.fullText ) )
end
if args.fromWikipedia then
table.insert( ret3,
mbox(
string.format(
"'''%s''' is imported from [https://en.wikipedia.org/wiki/%s %s] on Wikipedia.",
title.fullText,
page,
page
),
string.format(
'This %s is imported from the English Wikipedia. Although the visual appearance might be different, the functionality is identical. Please refer to the Wikipedia page for detailed documentation.',
pageType
),
{ icon = 'WikimediaUI-Logo-Wikipedia.svg' }
)
)
--- Set category
table.insert( ret3, string.format( '[[Category:%s imported from Wikipedia]]', lang:ucfirst( pageType ) .. 's' ) )
end
if title.namespace == 828 then
-- Has config
if mw.title.new( title.fullText .. '/config.json', 'Module' ).exists then
table.insert( ret3,
mbox(
string.format(
"'''%s''' loads configuration from [[%s/config.json]].",
title.fullText,
title.fullText
),
'This module can be configurated from the config.json subpage.',
{ icon='WikimediaUI-Settings.svg' }
)
)
end
-- Has localization
if mw.title.new( title.fullText .. '/i18n.json', 'Module' ).exists then
table.insert( ret3,
mbox(
string.format(
"'''%s''' loads messages from [[%s/i18n.json]].",
title.fullText,
title.fullText
),
'This module is designed to be language-neutral. All of the messages are saved in the i18n.json subpage.',
{ icon='WikimediaUI-Language.svg' }
)
)
end
-- Testcase page
if title.subpageText == 'testcases' then
table.insert( ret3,
hatnote(
string.format( 'This is the test cases page for the module [[Module:%s]].', title.baseText ),
{ icon='WikimediaUI-LabFlask.svg' }
)
)
end
end
--- Dependency list
table.insert( ret3, dependencyList._main( nil, args.category, args.isUsed ) )
-- Has templatestyles
if mw.title.new( title.fullText .. '/styles.css' ).exists then
table.insert( ret3,
hatnote(
string.format(
"'''%s''' loads styles from [[%s/styles.css]].",
title.fullText,
title.fullText
),
{ icon='WikimediaUI-Palette.svg' }
)
)
end
--- Module stats bar
if title.namespace == 828 then
table.insert( ret3, '<div class="documentation-modulestats">' )
-- Function list
table.insert( ret3, require( 'Module:Module toc' ).main() )
-- Unit tests
local testcaseTitle = title.baseText .. '/testcases'
if mw.title.new( testcaseTitle, 'Module' ).exists then
-- There is probably a better way :P
table.insert( ret3, frame:preprocess( '{{#invoke:' .. testcaseTitle .. '|run}}' ) )
end
table.insert( ret3, '</div>' )
end
return ret1 .. tostring( ret2 ) .. '<div class="documentation-content">' .. table.concat( ret3 )
end
return p
-- </nowiki>
5a5b6781058f69e3613197f6be6173d07d2bf085
Main Page
0
1
1
2024-01-11T00:17:07Z
MediaWiki default
1
Welcome to Miraheze!
wikitext
text/x-wiki
__NOTOC__
== Welcome to {{SITENAME}}! ==
This Main Page was created automatically and it seems it hasn't been replaced yet.
=== For the bureaucrat(s) of this wiki ===
Hello, and welcome to your new wiki! Thank you for choosing Miraheze for the hosting of your wiki, we hope you will enjoy our hosting.
You can immediately start working on your wiki or whenever you want.
Need help? No problem! We will help you with your wiki as needed. To start, try checking out these helpful links:
* [[mw:Special:MyLanguage/Help:Contents|MediaWiki guide]] (e.g. navigation, editing, deleting pages, blocking users)
* [[meta:Special:MyLanguage/FAQ|Miraheze FAQ]]
* [[meta:Special:MyLanguage/Request features|Request settings changes on your wiki]]. (Extensions, Skin and Logo/Favicon changes should be done through [[Special:ManageWiki]] on your wiki, see [[meta:Special:MyLanguage/ManageWiki|ManageWiki]] for more information.)
==== I still don't understand X! ====
Well, that's no problem. Even if something isn't explained in the documentation/FAQ, we are still happy to help you. You can find us here:
* [[meta:Special:MyLanguage/Help center|On our own Miraheze wiki]]
* On [[phab:|Phabricator]]
* On [https://miraheze.org/discord Discord]
* On IRC in #miraheze on irc.libera.chat ([irc://irc.libera.chat/%23miraheze direct link]; [https://web.libera.chat/?channel=#miraheze webchat])
=== For visitors of this wiki ===
Hello, the default Main Page of this wiki (this page) has not yet been replaced by the bureaucrat(s) of this wiki. The bureaucrat(s) might still be working on a Main Page, so please check again later!
21236ac3f8d65e5563b6da6b70815ca6bf1e6616
Template:Day
10
2
3
2
2024-01-11T08:30:40Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
<includeonly>'''{{{1|{{FULLPAGENAME}}}}}''' is the {{#switch:{{#time:z|{{{1|{{PAGENAME}}}}}}}
|0=first
|1=second
|2=third
|3=fourth
|4=fifth
|5=sixth
|6=seventh
|7=eighth
|8=ninth
|{{ordinal|{{#expr:{{#time:z|{{{1|{{PAGENAME}}}}}, 2001}}+1}}}}
}} day of the year{{#ifexpr:{{#time:n|{{{1|{{PAGENAME}}}}}}}<3
|
| ({{ordinal|{{#expr:{{#time:z|{{{1|{{PAGENAME}}}}}, 2000}}+1}}}} in leap years)
}} in the Gregorian calendar.{{#switch:{{#expr:364-{{#time:z|{{{1|{{PAGENAME}}}}}, 2001}}}}
|0=
|1= One day remains until the end of the year.
|2= Two days remain until the end of the year.
|3= Three days remain until the end of the year.
|4= Four days remain until the end of the year.
|5= Five days remain until the end of the year.
|6= Six days remain until the end of the year.
|7= Seven days remain until the end of the year.
|8= Eight days remain until the end of the year.
|9= Nine days remain until the end of the year.
|  {{#expr:364-{{#time:z|{{{1|{{PAGENAME}}}}}, 2001}}}} days remain until the end of the year{{#ifexpr:{{#time:n|{{{1|{{PAGENAME}}}}}}}<3
| ({{#expr:365-{{#time:z|{{{1|{{PAGENAME}}}}}, 2000}}}} in leap years)
|
}}.
}}</includeonly><noinclude>{{/doc}}</noinclude>
530dc54fd9473a69e2d1ff775d7d2b2a6c206768
Category:Alien language templates
14
3
5
4
2024-01-11T08:30:41Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
This category contains templates related displaying alien languages in article.
[[Category:Templates]]
31028d351947fb2c12f3d3976ef9be10d8ccdd76
Category:Article management templates
14
4
7
6
2024-01-11T08:30:41Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
A list of article management templates
[[Category:Templates]]
11b8b439968d60cbb1df76388c0e1e9b122ad13c
Category:Audio templates
14
5
9
8
2024-01-11T08:30:42Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Citation templates
14
7
13
12
2024-01-11T08:30:42Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:DPL templates
14
8
15
14
2024-01-11T08:30:43Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
This category contains templates which are designed solely for use with [https://help.gamepedia.com/Extension:DPL3/Manual DynamicPageList3].
For all page that uses DPL calls, see [[Special:WhatLinksHere/Template:Extension DPL]].
[[Category:Templates]]
2bb614cfa9d61ac951d5b671ebaa9bfbbd6fed0c
Category:External link templates
14
9
17
16
2024-01-11T08:30:43Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:File management templates
14
10
19
18
2024-01-11T08:30:43Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Formatting and function templates
14
11
21
20
2024-01-11T08:30:44Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:General wiki templates
14
12
23
22
2024-01-11T08:30:44Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Graph, chart, and plot templates
14
13
25
24
2024-01-11T08:30:45Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
{{Category header|templates|used to produce graphs}}
[[Category:Templates]]
d2eb48d7551d51c120fdbfa06a3981e0053afb31
Category:I18n templates
14
14
27
26
2024-01-11T08:30:45Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
'''I18n templates''' are templates contain repetitive words used in the whole wiki. The following templates help to reduce redundancy in translations and also serve as the standard translation for frequently used words.
[[Category:Templates]]
7717381b16fc84d004cf6f5bdaa73fa9febd0b07
Category:Infobox Templates
14
15
29
28
2024-01-11T08:30:46Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
See [[Help:Infoboxes]]
[[Category:Templates]]
50fb8af8e4d62b8e888bb9246e15a1806c52b2b5
Category:Infobox templates
14
16
31
30
2024-01-11T08:30:46Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Interface message templates
14
17
33
32
2024-01-11T08:30:47Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
{{Category header|templates|MediaWiki interface messages}}
[[Category:Templates]]
2ceb3a9c4b6b1e027d79edc01030738d73250add
Category:Internal link templates
14
18
35
34
2024-01-11T08:30:47Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Language templates
14
19
37
36
2024-01-11T08:30:48Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Lua-based templates
14
20
39
38
2024-01-11T08:30:48Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Main page templates
14
21
41
40
2024-01-11T08:30:49Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
{{Category header|templates|used on the main page}}
[[Category:Templates]]
fe5a1f6fb0db7ec3bd95014a7935715fb7558c94
Category:Maintenance templates
14
22
43
42
2024-01-11T08:30:49Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
This category contains templates related to ones that are used in articles that require maintenance.
[[Category:Templates]]
258ee9e751f38daed5ebb5a2281fa0f03311d340
Category:Manual templates
14
23
45
44
2024-01-11T08:30:50Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
Below are WIP templates that require manual update frequently as of now, and they are pending to be automated in the future.
[[Category:Templates]]
6b82ad760e14f78fdd70dc3f3d47ab254e57ff36
Category:Mathematical function templates
14
24
47
46
2024-01-11T08:30:50Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Navplates
14
25
49
48
2024-01-11T08:30:51Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
'''Navplates''' are navigation components that help visitor to visit pages that fall under the same category.
[[Category:Templates]]
ffa7595179dc81205203c976231a54a062e09851
Category:Number templates
14
26
51
50
2024-01-11T08:30:51Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
{{Category header|templates|manipulate number string}}
[[Category:Templates]]
8767a5b6f92ac0662e9e3feae33c87ecc776d542
Category:Numerical conversion templates
14
27
53
52
2024-01-11T08:30:51Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
{{Category header|templates|convert numbers}}
[[Category:Templates]]
8d11e0ccdfed85c0343603873eb362298ca75a25
Category:Preload text templates
14
28
55
54
2024-01-11T08:30:52Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
{{Category header|templates|used for article creation}}
[[Category:Templates]]
21360b4c5b0d6bef10209484084e8beb67641662
Category:SEO templates
14
29
57
56
2024-01-11T08:30:52Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
One of these templates should be included in all page in the main namespace
[[Category:Templates]]
0a8943c2a2dbff16b4685086e66c2086c7d39367
Category:String manipulation templates
14
31
61
60
2024-01-11T08:30:53Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Substitution only templates
14
32
63
62
2024-01-11T08:30:53Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Templates imported from Wikipedia
14
33
65
64
2024-01-11T08:30:53Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Templates using TemplateStyles
14
34
67
66
2024-01-11T08:30:54Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
{{Category header|templates|using [[Star Citizen:TemplateStyles|TemplateStyles]]}}
[[Category:Templates]]
7281aa1e395de9d8c368a3975548ace744177ec3
Category:Typing-aid templates
14
35
69
68
2024-01-11T08:30:55Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Under-construction templates
14
36
71
70
2024-01-11T08:30:55Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Utility templates
14
37
73
72
2024-01-11T08:30:55Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
{{Category header|templates|that are not suitable to use directly on pages. They should only be used in templates|related=no}}
[[Category:Templates]]
8ef6eadc680eea4f36a48b5fbf988cab1768b2ef
Category:Vehicle Specification Templates
14
38
75
74
2024-01-11T08:30:56Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Category:Vehicle specification templates
14
39
77
76
2024-01-11T08:30:56Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
[[Category:Templates]]
06eecdec29f6cb215c99cf216d1e3bdc8c30a95e
Module:Arguments
828
40
79
78
2024-01-11T08:30:57Z
EvaTheServal
2
1 revision imported
Scribunto
text/plain
-- This module provides easy processing of arguments passed to Scribunto from
-- #invoke. It is intended for use by other Lua modules, and should not be
-- called from #invoke directly.
local libraryUtil = require('libraryUtil')
local checkType = libraryUtil.checkType
local arguments = {}
-- Generate four different tidyVal functions, so that we don't have to check the
-- options every time we call it.
local function tidyValDefault(key, val)
if type(val) == 'string' then
val = val:match('^%s*(.-)%s*$')
if val == '' then
return nil
else
return val
end
else
return val
end
end
local function tidyValTrimOnly(key, val)
if type(val) == 'string' then
return val:match('^%s*(.-)%s*$')
else
return val
end
end
local function tidyValRemoveBlanksOnly(key, val)
if type(val) == 'string' then
if val:find('%S') then
return val
else
return nil
end
else
return val
end
end
local function tidyValNoChange(key, val)
return val
end
local function matchesTitle(given, title)
local tp = type( given )
return (tp == 'string' or tp == 'number') and mw.title.new( given ).prefixedText == title
end
local translate_mt = { __index = function(t, k) return k end }
function arguments.getArgs(frame, options)
checkType('getArgs', 1, frame, 'table', true)
checkType('getArgs', 2, options, 'table', true)
frame = frame or {}
options = options or {}
--[[
-- Set up argument translation.
--]]
options.translate = options.translate or {}
if getmetatable(options.translate) == nil then
setmetatable(options.translate, translate_mt)
end
if options.backtranslate == nil then
options.backtranslate = {}
for k,v in pairs(options.translate) do
options.backtranslate[v] = k
end
end
if options.backtranslate and getmetatable(options.backtranslate) == nil then
setmetatable(options.backtranslate, {
__index = function(t, k)
if options.translate[k] ~= k then
return nil
else
return k
end
end
})
end
--[[
-- Get the argument tables. If we were passed a valid frame object, get the
-- frame arguments (fargs) and the parent frame arguments (pargs), depending
-- on the options set and on the parent frame's availability. If we weren't
-- passed a valid frame object, we are being called from another Lua module
-- or from the debug console, so assume that we were passed a table of args
-- directly, and assign it to a new variable (luaArgs).
--]]
local fargs, pargs, luaArgs
if type(frame.args) == 'table' and type(frame.getParent) == 'function' then
if options.wrappers then
--[[
-- The wrappers option makes Module:Arguments look up arguments in
-- either the frame argument table or the parent argument table, but
-- not both. This means that users can use either the #invoke syntax
-- or a wrapper template without the loss of performance associated
-- with looking arguments up in both the frame and the parent frame.
-- Module:Arguments will look up arguments in the parent frame
-- if it finds the parent frame's title in options.wrapper;
-- otherwise it will look up arguments in the frame object passed
-- to getArgs.
--]]
local parent = frame:getParent()
if not parent then
fargs = frame.args
else
local title = parent:getTitle():gsub('/sandbox$', '')
local found = false
if matchesTitle(options.wrappers, title) then
found = true
elseif type(options.wrappers) == 'table' then
for _,v in pairs(options.wrappers) do
if matchesTitle(v, title) then
found = true
break
end
end
end
-- We test for false specifically here so that nil (the default) acts like true.
if found or options.frameOnly == false then
pargs = parent.args
end
if not found or options.parentOnly == false then
fargs = frame.args
end
end
else
-- options.wrapper isn't set, so check the other options.
if not options.parentOnly then
fargs = frame.args
end
if not options.frameOnly then
local parent = frame:getParent()
pargs = parent and parent.args or nil
end
end
if options.parentFirst then
fargs, pargs = pargs, fargs
end
else
luaArgs = frame
end
-- Set the order of precedence of the argument tables. If the variables are
-- nil, nothing will be added to the table, which is how we avoid clashes
-- between the frame/parent args and the Lua args.
local argTables = {fargs}
argTables[#argTables + 1] = pargs
argTables[#argTables + 1] = luaArgs
--[[
-- Generate the tidyVal function. If it has been specified by the user, we
-- use that; if not, we choose one of four functions depending on the
-- options chosen. This is so that we don't have to call the options table
-- every time the function is called.
--]]
local tidyVal = options.valueFunc
if tidyVal then
if type(tidyVal) ~= 'function' then
error(
"bad value assigned to option 'valueFunc'"
.. '(function expected, got '
.. type(tidyVal)
.. ')',
2
)
end
elseif options.trim ~= false then
if options.removeBlanks ~= false then
tidyVal = tidyValDefault
else
tidyVal = tidyValTrimOnly
end
else
if options.removeBlanks ~= false then
tidyVal = tidyValRemoveBlanksOnly
else
tidyVal = tidyValNoChange
end
end
--[[
-- Set up the args, metaArgs and nilArgs tables. args will be the one
-- accessed from functions, and metaArgs will hold the actual arguments. Nil
-- arguments are memoized in nilArgs, and the metatable connects all of them
-- together.
--]]
local args, metaArgs, nilArgs, metatable = {}, {}, {}, {}
setmetatable(args, metatable)
local function mergeArgs(tables)
--[[
-- Accepts multiple tables as input and merges their keys and values
-- into one table. If a value is already present it is not overwritten;
-- tables listed earlier have precedence. We are also memoizing nil
-- values, which can be overwritten if they are 's' (soft).
--]]
for _, t in ipairs(tables) do
for key, val in pairs(t) do
if metaArgs[key] == nil and nilArgs[key] ~= 'h' then
local tidiedVal = tidyVal(key, val)
if tidiedVal == nil then
nilArgs[key] = 's'
else
metaArgs[key] = tidiedVal
end
end
end
end
end
--[[
-- Define metatable behaviour. Arguments are memoized in the metaArgs table,
-- and are only fetched from the argument tables once. Fetching arguments
-- from the argument tables is the most resource-intensive step in this
-- module, so we try and avoid it where possible. For this reason, nil
-- arguments are also memoized, in the nilArgs table. Also, we keep a record
-- in the metatable of when pairs and ipairs have been called, so we do not
-- run pairs and ipairs on the argument tables more than once. We also do
-- not run ipairs on fargs and pargs if pairs has already been run, as all
-- the arguments will already have been copied over.
--]]
metatable.__index = function (t, key)
--[[
-- Fetches an argument when the args table is indexed. First we check
-- to see if the value is memoized, and if not we try and fetch it from
-- the argument tables. When we check memoization, we need to check
-- metaArgs before nilArgs, as both can be non-nil at the same time.
-- If the argument is not present in metaArgs, we also check whether
-- pairs has been run yet. If pairs has already been run, we return nil.
-- This is because all the arguments will have already been copied into
-- metaArgs by the mergeArgs function, meaning that any other arguments
-- must be nil.
--]]
if type(key) == 'string' then
key = options.translate[key]
end
local val = metaArgs[key]
if val ~= nil then
return val
elseif metatable.donePairs or nilArgs[key] then
return nil
end
for _, argTable in ipairs(argTables) do
local argTableVal = tidyVal(key, argTable[key])
if argTableVal ~= nil then
metaArgs[key] = argTableVal
return argTableVal
end
end
nilArgs[key] = 'h'
return nil
end
metatable.__newindex = function (t, key, val)
-- This function is called when a module tries to add a new value to the
-- args table, or tries to change an existing value.
if type(key) == 'string' then
key = options.translate[key]
end
if options.readOnly then
error(
'could not write to argument table key "'
.. tostring(key)
.. '"; the table is read-only',
2
)
elseif options.noOverwrite and args[key] ~= nil then
error(
'could not write to argument table key "'
.. tostring(key)
.. '"; overwriting existing arguments is not permitted',
2
)
elseif val == nil then
--[[
-- If the argument is to be overwritten with nil, we need to erase
-- the value in metaArgs, so that __index, __pairs and __ipairs do
-- not use a previous existing value, if present; and we also need
-- to memoize the nil in nilArgs, so that the value isn't looked
-- up in the argument tables if it is accessed again.
--]]
metaArgs[key] = nil
nilArgs[key] = 'h'
else
metaArgs[key] = val
end
end
local function translatenext(invariant)
local k, v = next(invariant.t, invariant.k)
invariant.k = k
if k == nil then
return nil
elseif type(k) ~= 'string' or not options.backtranslate then
return k, v
else
local backtranslate = options.backtranslate[k]
if backtranslate == nil then
-- Skip this one. This is a tail call, so this won't cause stack overflow
return translatenext(invariant)
else
return backtranslate, v
end
end
end
metatable.__pairs = function ()
-- Called when pairs is run on the args table.
if not metatable.donePairs then
mergeArgs(argTables)
metatable.donePairs = true
end
return translatenext, { t = metaArgs }
end
local function inext(t, i)
-- This uses our __index metamethod
local v = t[i + 1]
if v ~= nil then
return i + 1, v
end
end
metatable.__ipairs = function (t)
-- Called when ipairs is run on the args table.
return inext, t, 0
end
return args
end
return arguments
3134ecce8429b810d445e29eae115e2ae4c36c53
Module:Hatnote
828
41
81
80
2024-01-11T08:30:59Z
EvaTheServal
2
1 revision imported
Scribunto
text/plain
--------------------------------------------------------------------------------
-- Module:Hatnote --
-- --
-- This module produces hatnote links and links to related articles. It --
-- implements the {{hatnote}} and {{format link}} meta-templates and includes --
-- helper functions for other Lua hatnote modules. --
--------------------------------------------------------------------------------
local libraryUtil = require('libraryUtil')
local checkType = libraryUtil.checkType
local mArguments -- lazily initialise [[Module:Arguments]]
local yesno -- lazily initialise [[Module:Yesno]]
local p = {}
--------------------------------------------------------------------------------
-- Helper functions
--------------------------------------------------------------------------------
local function getArgs(frame)
-- Fetches the arguments from the parent frame. Whitespace is trimmed and
-- blanks are removed.
mArguments = require('Module:Arguments')
return mArguments.getArgs(frame, {parentOnly = true})
end
local function removeInitialColon(s)
-- Removes the initial colon from a string, if present.
return s:match('^:?(.*)')
end
function p.defaultClasses(inline)
-- Provides the default hatnote classes as a space-separated string; useful
-- for hatnote-manipulation modules like [[Module:Hatnote group]].
return
(inline == 1 and 'hatnote-inline' or 'hatnote') .. ' ' ..
'navigation-not-searchable'
end
function p.disambiguate(page, disambiguator)
-- Formats a page title with a disambiguation parenthetical,
-- i.e. "Example" → "Example (disambiguation)".
checkType('disambiguate', 1, page, 'string')
checkType('disambiguate', 2, disambiguator, 'string', true)
disambiguator = disambiguator or 'disambiguation'
return mw.ustring.format('%s (%s)', page, disambiguator)
end
function p.findNamespaceId(link, removeColon)
-- Finds the namespace id (namespace number) of a link or a pagename. This
-- function will not work if the link is enclosed in double brackets. Colons
-- are trimmed from the start of the link by default. To skip colon
-- trimming, set the removeColon parameter to false.
checkType('findNamespaceId', 1, link, 'string')
checkType('findNamespaceId', 2, removeColon, 'boolean', true)
if removeColon ~= false then
link = removeInitialColon(link)
end
local namespace = link:match('^(.-):')
if namespace then
local nsTable = mw.site.namespaces[namespace]
if nsTable then
return nsTable.id
end
end
return 0
end
function p.makeWikitextError(msg, helpLink, addTrackingCategory, title)
-- Formats an error message to be returned to wikitext. If
-- addTrackingCategory is not false after being returned from
-- [[Module:Yesno]], and if we are not on a talk page, a tracking category
-- is added.
checkType('makeWikitextError', 1, msg, 'string')
checkType('makeWikitextError', 2, helpLink, 'string', true)
yesno = require('Module:Yesno')
title = title or mw.title.getCurrentTitle()
-- Make the help link text.
local helpText
if helpLink then
helpText = ' ([[' .. helpLink .. '|help]])'
else
helpText = ''
end
-- Make the category text.
local category
if not title.isTalkPage -- Don't categorise talk pages
and title.namespace ~= 2 -- Don't categorise userspace
and yesno(addTrackingCategory) ~= false -- Allow opting out
then
category = 'Hatnote templates with errors'
category = mw.ustring.format(
'[[%s:%s]]',
mw.site.namespaces[14].name,
category
)
else
category = ''
end
return mw.ustring.format(
'<strong class="error">Error: %s%s.</strong>%s',
msg,
helpText,
category
)
end
local curNs = mw.title.getCurrentTitle().namespace
p.missingTargetCat =
--Default missing target category, exported for use in related modules
((curNs == 0) or (curNs == 14)) and
'Articles with hatnote templates targeting a nonexistent page' or nil
function p.quote(title)
--Wraps titles in quotation marks. If the title starts/ends with a quotation
--mark, kerns that side as with {{-'}}
local quotationMarks = {
["'"]=true, ['"']=true, ['“']=true, ["‘"]=true, ['”']=true, ["’"]=true
}
local quoteLeft, quoteRight = -- Test if start/end are quotation marks
quotationMarks[string.sub(title, 1, 1)],
quotationMarks[string.sub(title, -1, -1)]
if quoteLeft or quoteRight then
title = mw.html.create("span"):wikitext(title)
end
if quoteLeft then title:css("padding-left", "0.15em") end
if quoteRight then title:css("padding-right", "0.15em") end
return '"' .. tostring(title) .. '"'
end
--------------------------------------------------------------------------------
-- Hatnote
--
-- Produces standard hatnote text. Implements the {{hatnote}} template.
--------------------------------------------------------------------------------
local function decorateHatnote(hatnote, options)
local function getIcon(filename)
local html = ''
if type(filename) == 'string' then
local icon = mw.html.create('span')
icon
:addClass('hatnote-icon')
:addClass('metadata')
:wikitext('[[File:' .. filename .. '|14px|link=]]')
:done()
html = tostring(icon)
end
return html
end
local container = mw.html.create('div')
container
:addClass('hatnote-container')
:wikitext(getIcon(options.icon))
:wikitext(tostring(hatnote))
:done()
return container
end
function p.hatnote(frame)
local args = getArgs(frame)
local s = args[1]
if not s then
return p.makeWikitextError(
'no text specified',
'Template:Hatnote#Errors',
args.category
)
end
return p._hatnote(s, {
extraclasses = args.extraclasses,
selfref = args.selfref
})
end
function p._hatnote(s, options)
checkType('_hatnote', 1, s, 'string')
checkType('_hatnote', 2, options, 'table', true)
options = options or {}
local inline = options.inline
local hatnote = mw.html.create(inline == 1 and 'span' or 'div')
local extraclasses
if type(options.extraclasses) == 'string' then
extraclasses = options.extraclasses
end
hatnote
:attr('role', 'note')
:addClass(p.defaultClasses(inline))
:addClass(extraclasses)
:addClass(options.selfref and 'selfref' or nil)
:wikitext(s)
-- Decorate WP hatnote to SCW standard
hatnote = decorateHatnote(hatnote, options)
return mw.getCurrentFrame():extensionTag{
name = 'templatestyles', args = { src = 'Module:Hatnote/styles.css' }
} .. tostring(hatnote)
end
return p
7e322cb6950c0f36959bceccc679cc8f52959f7c
Template:Note
10
42
83
82
2024-01-11T08:30:59Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
#REDIRECT [[Template:Hatnote]]
9582e82fbead373024765d896e4930eee521d846
Module:String
828
43
85
84
2024-01-11T08:31:00Z
EvaTheServal
2
1 revision imported
Scribunto
text/plain
--[[
This module is intended to provide access to basic string functions.
Most of the functions provided here can be invoked with named parameters,
unnamed parameters, or a mixture. If named parameters are used, Mediawiki will
automatically remove any leading or trailing whitespace from the parameter.
Depending on the intended use, it may be advantageous to either preserve or
remove such whitespace.
Global options
ignore_errors: If set to 'true' or 1, any error condition will result in
an empty string being returned rather than an error message.
error_category: If an error occurs, specifies the name of a category to
include with the error message. The default category is
[Category:Errors reported by Module String].
no_category: If set to 'true' or 1, no category will be added if an error
is generated.
Unit tests for this module are available at Module:String/tests.
]]
local str = {}
--[[
len
This function returns the length of the target string.
Usage:
{{#invoke:String|len|target_string|}}
OR
{{#invoke:String|len|s=target_string}}
Parameters
s: The string whose length to report
If invoked using named parameters, Mediawiki will automatically remove any leading or
trailing whitespace from the target string.
]]
function str.len( frame )
local new_args = str._getParameters( frame.args, {'s'} )
local s = new_args['s'] or ''
return mw.ustring.len( s )
end
--[[
sub
This function returns a substring of the target string at specified indices.
Usage:
{{#invoke:String|sub|target_string|start_index|end_index}}
OR
{{#invoke:String|sub|s=target_string|i=start_index|j=end_index}}
Parameters
s: The string to return a subset of
i: The fist index of the substring to return, defaults to 1.
j: The last index of the string to return, defaults to the last character.
The first character of the string is assigned an index of 1. If either i or j
is a negative value, it is interpreted the same as selecting a character by
counting from the end of the string. Hence, a value of -1 is the same as
selecting the last character of the string.
If the requested indices are out of range for the given string, an error is
reported.
]]
function str.sub( frame )
local new_args = str._getParameters( frame.args, { 's', 'i', 'j' } )
local s = new_args['s'] or ''
local i = tonumber( new_args['i'] ) or 1
local j = tonumber( new_args['j'] ) or -1
local len = mw.ustring.len( s )
-- Convert negatives for range checking
if i < 0 then
i = len + i + 1
end
if j < 0 then
j = len + j + 1
end
if i > len or j > len or i < 1 or j < 1 then
return str._error( 'String subset index out of range' )
end
if j < i then
return str._error( 'String subset indices out of order' )
end
return mw.ustring.sub( s, i, j )
end
--[[
This function implements that features of {{str sub old}} and is kept in order
to maintain these older templates.
]]
function str.sublength( frame )
local i = tonumber( frame.args.i ) or 0
local len = tonumber( frame.args.len )
return mw.ustring.sub( frame.args.s, i + 1, len and ( i + len ) )
end
--[[
_match
This function returns a substring from the source string that matches a
specified pattern. It is exported for use in other modules
Usage:
strmatch = require("Module:String")._match
sresult = strmatch( s, pattern, start, match, plain, nomatch )
Parameters
s: The string to search
pattern: The pattern or string to find within the string
start: The index within the source string to start the search. The first
character of the string has index 1. Defaults to 1.
match: In some cases it may be possible to make multiple matches on a single
string. This specifies which match to return, where the first match is
match= 1. If a negative number is specified then a match is returned
counting from the last match. Hence match = -1 is the same as requesting
the last match. Defaults to 1.
plain: A flag indicating that the pattern should be understood as plain
text. Defaults to false.
nomatch: If no match is found, output the "nomatch" value rather than an error.
For information on constructing Lua patterns, a form of [regular expression], see:
* http://www.lua.org/manual/5.1/manual.html#5.4.1
* http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Patterns
* http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Ustring_patterns
]]
-- This sub-routine is exported for use in other modules
function str._match( s, pattern, start, match_index, plain_flag, nomatch )
if s == '' then
return str._error( 'Target string is empty' )
end
if pattern == '' then
return str._error( 'Pattern string is empty' )
end
start = tonumber(start) or 1
if math.abs(start) < 1 or math.abs(start) > mw.ustring.len( s ) then
return str._error( 'Requested start is out of range' )
end
if match_index == 0 then
return str._error( 'Match index is out of range' )
end
if plain_flag then
pattern = str._escapePattern( pattern )
end
local result
if match_index == 1 then
-- Find first match is simple case
result = mw.ustring.match( s, pattern, start )
else
if start > 1 then
s = mw.ustring.sub( s, start )
end
local iterator = mw.ustring.gmatch(s, pattern)
if match_index > 0 then
-- Forward search
for w in iterator do
match_index = match_index - 1
if match_index == 0 then
result = w
break
end
end
else
-- Reverse search
local result_table = {}
local count = 1
for w in iterator do
result_table[count] = w
count = count + 1
end
result = result_table[ count + match_index ]
end
end
if result == nil then
if nomatch == nil then
return str._error( 'Match not found' )
else
return nomatch
end
else
return result
end
end
--[[
match
This function returns a substring from the source string that matches a
specified pattern.
Usage:
{{#invoke:String|match|source_string|pattern_string|start_index|match_number|plain_flag|nomatch_output}}
OR
{{#invoke:String|match|s=source_string|pattern=pattern_string|start=start_index
|match=match_number|plain=plain_flag|nomatch=nomatch_output}}
Parameters
s: The string to search
pattern: The pattern or string to find within the string
start: The index within the source string to start the search. The first
character of the string has index 1. Defaults to 1.
match: In some cases it may be possible to make multiple matches on a single
string. This specifies which match to return, where the first match is
match= 1. If a negative number is specified then a match is returned
counting from the last match. Hence match = -1 is the same as requesting
the last match. Defaults to 1.
plain: A flag indicating that the pattern should be understood as plain
text. Defaults to false.
nomatch: If no match is found, output the "nomatch" value rather than an error.
If invoked using named parameters, Mediawiki will automatically remove any leading or
trailing whitespace from each string. In some circumstances this is desirable, in
other cases one may want to preserve the whitespace.
If the match_number or start_index are out of range for the string being queried, then
this function generates an error. An error is also generated if no match is found.
If one adds the parameter ignore_errors=true, then the error will be suppressed and
an empty string will be returned on any failure.
For information on constructing Lua patterns, a form of [regular expression], see:
* http://www.lua.org/manual/5.1/manual.html#5.4.1
* http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Patterns
* http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Ustring_patterns
]]
-- This is the entry point for #invoke:String|match
function str.match( frame )
local new_args = str._getParameters( frame.args, {'s', 'pattern', 'start', 'match', 'plain', 'nomatch'} )
local s = new_args['s'] or ''
local start = tonumber( new_args['start'] ) or 1
local plain_flag = str._getBoolean( new_args['plain'] or false )
local pattern = new_args['pattern'] or ''
local match_index = math.floor( tonumber(new_args['match']) or 1 )
local nomatch = new_args['nomatch']
return str._match( s, pattern, start, match_index, plain_flag, nomatch )
end
--[[
pos
This function returns a single character from the target string at position pos.
Usage:
{{#invoke:String|pos|target_string|index_value}}
OR
{{#invoke:String|pos|target=target_string|pos=index_value}}
Parameters
target: The string to search
pos: The index for the character to return
If invoked using named parameters, Mediawiki will automatically remove any leading or
trailing whitespace from the target string. In some circumstances this is desirable, in
other cases one may want to preserve the whitespace.
The first character has an index value of 1.
If one requests a negative value, this function will select a character by counting backwards
from the end of the string. In other words pos = -1 is the same as asking for the last character.
A requested value of zero, or a value greater than the length of the string returns an error.
]]
function str.pos( frame )
local new_args = str._getParameters( frame.args, {'target', 'pos'} )
local target_str = new_args['target'] or ''
local pos = tonumber( new_args['pos'] ) or 0
if pos == 0 or math.abs(pos) > mw.ustring.len( target_str ) then
return str._error( 'String index out of range' )
end
return mw.ustring.sub( target_str, pos, pos )
end
--[[
str_find
This function duplicates the behavior of {{str_find}}, including all of its quirks.
This is provided in order to support existing templates, but is NOT RECOMMENDED for
new code and templates. New code is recommended to use the "find" function instead.
Returns the first index in "source" that is a match to "target". Indexing is 1-based,
and the function returns -1 if the "target" string is not present in "source".
Important Note: If the "target" string is empty / missing, this function returns a
value of "1", which is generally unexpected behavior, and must be accounted for
separatetly.
]]
function str.str_find( frame )
local new_args = str._getParameters( frame.args, {'source', 'target'} )
local source_str = new_args['source'] or ''
local target_str = new_args['target'] or ''
if target_str == '' then
return 1
end
local start = mw.ustring.find( source_str, target_str, 1, true )
if start == nil then
start = -1
end
return start
end
--[[
find
This function allows one to search for a target string or pattern within another
string.
Usage:
{{#invoke:String|find|source_str|target_string|start_index|plain_flag}}
OR
{{#invoke:String|find|source=source_str|target=target_str|start=start_index|plain=plain_flag}}
Parameters
source: The string to search
target: The string or pattern to find within source
start: The index within the source string to start the search, defaults to 1
plain: Boolean flag indicating that target should be understood as plain
text and not as a Lua style regular expression, defaults to true
If invoked using named parameters, Mediawiki will automatically remove any leading or
trailing whitespace from the parameter. In some circumstances this is desirable, in
other cases one may want to preserve the whitespace.
This function returns the first index >= "start" where "target" can be found
within "source". Indices are 1-based. If "target" is not found, then this
function returns 0. If either "source" or "target" are missing / empty, this
function also returns 0.
This function should be safe for UTF-8 strings.
]]
function str.find( frame )
local new_args = str._getParameters( frame.args, {'source', 'target', 'start', 'plain' } )
local source_str = new_args['source'] or ''
local pattern = new_args['target'] or ''
local start_pos = tonumber(new_args['start']) or 1
local plain = new_args['plain'] or true
if source_str == '' or pattern == '' then
return 0
end
plain = str._getBoolean( plain )
local start = mw.ustring.find( source_str, pattern, start_pos, plain )
if start == nil then
start = 0
end
return start
end
--[[
replace
This function allows one to replace a target string or pattern within another
string.
Usage:
{{#invoke:String|replace|source_str|pattern_string|replace_string|replacement_count|plain_flag}}
OR
{{#invoke:String|replace|source=source_string|pattern=pattern_string|replace=replace_string|
count=replacement_count|plain=plain_flag}}
Parameters
source: The string to search
pattern: The string or pattern to find within source
replace: The replacement text
count: The number of occurences to replace, defaults to all.
plain: Boolean flag indicating that pattern should be understood as plain
text and not as a Lua style regular expression, defaults to true
]]
function str.replace( frame )
local new_args = str._getParameters( frame.args, {'source', 'pattern', 'replace', 'count', 'plain' } )
local source_str = new_args['source'] or ''
local pattern = new_args['pattern'] or ''
local replace = new_args['replace'] or ''
local count = tonumber( new_args['count'] )
local plain = new_args['plain'] or true
if source_str == '' or pattern == '' then
return source_str
end
plain = str._getBoolean( plain )
if plain then
pattern = str._escapePattern( pattern )
replace = mw.ustring.gsub( replace, "%%", "%%%%" ) --Only need to escape replacement sequences.
end
local result
if count ~= nil then
result = mw.ustring.gsub( source_str, pattern, replace, count )
else
result = mw.ustring.gsub( source_str, pattern, replace )
end
return result
end
--[[
simple function to pipe string.rep to templates.
]]
function str.rep( frame )
local repetitions = tonumber( frame.args[2] )
if not repetitions then
return str._error( 'function rep expects a number as second parameter, received "' .. ( frame.args[2] or '' ) .. '"' )
end
return string.rep( frame.args[1] or '', repetitions )
end
--[[
escapePattern
This function escapes special characters from a Lua string pattern. See [1]
for details on how patterns work.
[1] https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#Patterns
Usage:
{{#invoke:String|escapePattern|pattern_string}}
Parameters
pattern_string: The pattern string to escape.
]]
function str.escapePattern( frame )
local pattern_str = frame.args[1]
if not pattern_str then
return str._error( 'No pattern string specified' )
end
local result = str._escapePattern( pattern_str )
return result
end
--[[
count
This function counts the number of occurrences of one string in another.
]]
function str.count(frame)
local args = str._getParameters(frame.args, {'source', 'pattern', 'plain'})
local source = args.source or ''
local pattern = args.pattern or ''
local plain = str._getBoolean(args.plain or true)
if plain then
pattern = str._escapePattern(pattern)
end
local _, count = mw.ustring.gsub(source, pattern, '')
return count
end
--[[
endswith
This function determines whether a string ends with another string.
]]
function str.endswith(frame)
local args = str._getParameters(frame.args, {'source', 'pattern'})
local source = args.source or ''
local pattern = args.pattern or ''
if pattern == '' then
-- All strings end with the empty string.
return "yes"
end
if mw.ustring.sub(source, -mw.ustring.len(pattern), -1) == pattern then
return "yes"
else
return ""
end
end
--[[
join
Join all non empty arguments together; the first argument is the separator.
Usage:
{{#invoke:String|join|sep|one|two|three}}
]]
function str.join(frame)
local args = {}
local sep
for _, v in ipairs( frame.args ) do
if sep then
if v ~= '' then
table.insert(args, v)
end
else
sep = v
end
end
return table.concat( args, sep or '' )
end
--[[
Helper function that populates the argument list given that user may need to use a mix of
named and unnamed parameters. This is relevant because named parameters are not
identical to unnamed parameters due to string trimming, and when dealing with strings
we sometimes want to either preserve or remove that whitespace depending on the application.
]]
function str._getParameters( frame_args, arg_list )
local new_args = {}
local index = 1
local value
for _, arg in ipairs( arg_list ) do
value = frame_args[arg]
if value == nil then
value = frame_args[index]
index = index + 1
end
new_args[arg] = value
end
return new_args
end
--[[
Helper function to handle error messages.
]]
function str._error( error_str )
local frame = mw.getCurrentFrame()
local error_category = frame.args.error_category or 'Errors reported by Module String'
local ignore_errors = frame.args.ignore_errors or false
local no_category = frame.args.no_category or false
if str._getBoolean(ignore_errors) then
return ''
end
local error_str = '<strong class="error">String Module Error: ' .. error_str .. '</strong>'
if error_category ~= '' and not str._getBoolean( no_category ) then
error_str = '[[Category:' .. error_category .. ']]' .. error_str
end
return error_str
end
--[[
Helper Function to interpret boolean strings
]]
function str._getBoolean( boolean_str )
local boolean_value
if type( boolean_str ) == 'string' then
boolean_str = boolean_str:lower()
if boolean_str == 'false' or boolean_str == 'no' or boolean_str == '0'
or boolean_str == '' then
boolean_value = false
else
boolean_value = true
end
elseif type( boolean_str ) == 'boolean' then
boolean_value = boolean_str
else
error( 'No boolean value found' )
end
return boolean_value
end
--[[
Helper function that escapes all pattern characters so that they will be treated
as plain text.
]]
function str._escapePattern( pattern_str )
return mw.ustring.gsub( pattern_str, "([%(%)%.%%%+%-%*%?%[%^%$%]])", "%%%1" )
end
return str
6df794dd52434e0f6a372c9918f5a9dedd15f579
Template:Nbsp
10
44
87
86
2024-01-11T08:31:01Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
#REDIRECT [[Template:Spaces]]
d55076009c86bad01caacd67c545037409e5e1ee
Template:Spaces
10
45
89
88
2024-01-11T08:31:02Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
<span class="nowrap">{{#iferror:{{#expr:{{{1|1}}}}}
|{{#switch:{{{1}}}
|fig= 
|en= 
|em= 
|thin= 
|hair= 
|
}}
|{{#invoke:String|rep|{{#switch:{{{2}}}
|fig= 
|en= 
|em= 
|thin= 
|hair= 
|
}}|{{{1|1}}}}}
}}</span><noinclude>
{{/doc}}
</noinclude>
17efb36433f45a5c4f23528902387edcf0e174f0
Template:Category header
10
46
91
90
2024-01-11T08:31:02Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
<includeonly>{{Note|This category contains {{{1}}}{{#if:{{{2|}}}|{{#ifeq:{{lc:{{{related|}}}}}|no||{{nbsp}}related to}}{{nbsp}}{{{2}}}}}. {{#if:{{{3|}}}|This category is automatically added by {{{4|}}}.}}}}</includeonly><noinclude>{{/doc}}</noinclude>
a396b20e4e0c621cc7538e9a0f085cfbbd37a811
Module:Hatnote/styles.css
828
47
93
92
2024-01-11T08:31:03Z
EvaTheServal
2
1 revision imported
text
text/plain
.hatnote-container {
display: flex;
align-items: center;
padding: var( --space-sm ) var( --space-md );
margin-top: var( --space-xs );
margin-bottom: var( --space-md );
background: var( --color-surface-2 );
border-radius: var( --border-radius--medium );
color: var( --color-base--subtle );
font-size: 0.875rem;
line-height: var( --line-height-xs );
}
.hatnote-icon img {
width: 14px;
height: auto;
margin-right: var( --space-xs );
opacity: var( --opacity-icon-base );
}
/* Dark theme */
html.skin-citizen-dark .hatnote-icon img {
filter: invert( 1 );
}
44850b74680c356f2514e4292d2130fb67f3b46d
Template:Hatnote
10
48
95
94
2024-01-11T08:31:03Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
<includeonly>{{#invoke:Hatnote|hatnote}}</includeonly><noinclude>{{/doc}}</noinclude>
d9029e1bc2de056708cda99e6ce883644c1661e4
Template:Infobox
10
49
97
96
2024-01-11T08:38:08Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
{{#invoke:Infobox|infobox}}<noinclude>
{{/doc}}
<!-- Categories go in the /doc subpage, and interwikis go in Wikidata. -->
</noinclude>
aaadab5f0433ae495a07ed115145bf7ca42d5c10
Module:Hatnote list
828
50
99
98
2024-01-11T08:38:09Z
EvaTheServal
2
1 revision imported
Scribunto
text/plain
--------------------------------------------------------------------------------
-- Module:Hatnote list --
-- --
-- This module produces and formats lists for use in hatnotes. In particular, --
-- it implements the for-see list, i.e. lists of "For X, see Y" statements, --
-- as used in {{about}}, {{redirect}}, and their variants. Also introduced --
-- are andList & orList helpers for formatting lists with those conjunctions. --
--------------------------------------------------------------------------------
local mArguments --initialize lazily
local mFormatLink = require('Module:Format link')
local mHatnote = require('Module:Hatnote')
local libraryUtil = require('libraryUtil')
local checkType = libraryUtil.checkType
local p = {}
--------------------------------------------------------------------------------
-- List stringification helper functions
--
-- These functions are used for stringifying lists, usually page lists inside
-- the "Y" portion of "For X, see Y" for-see items.
--------------------------------------------------------------------------------
--default options table used across the list stringification functions
local stringifyListDefaultOptions = {
conjunction = "and",
separator = ",",
altSeparator = ";",
space = " ",
formatted = false
}
--Searches display text only
local function searchDisp(haystack, needle)
return string.find(
string.sub(haystack, (string.find(haystack, '|') or 0) + 1), needle
)
end
-- Stringifies a list generically; probably shouldn't be used directly
local function stringifyList(list, options)
-- Type-checks, defaults, and a shortcut
checkType("stringifyList", 1, list, "table")
if #list == 0 then return nil end
checkType("stringifyList", 2, options, "table", true)
options = options or {}
for k, v in pairs(stringifyListDefaultOptions) do
if options[k] == nil then options[k] = v end
end
local s = options.space
-- Format the list if requested
if options.formatted then
list = mFormatLink.formatPages(
{categorizeMissing = mHatnote.missingTargetCat}, list
)
end
-- Set the separator; if any item contains it, use the alternate separator
local separator = options.separator
for k, v in pairs(list) do
if searchDisp(v, separator) then
separator = options.altSeparator
break
end
end
-- Set the conjunction, apply Oxford comma, and force a comma if #1 has "§"
local conjunction = s .. options.conjunction .. s
if #list == 2 and searchDisp(list[1], "§") or #list > 2 then
conjunction = separator .. conjunction
end
-- Return the formatted string
return mw.text.listToText(list, separator .. s, conjunction)
end
--DRY function
function p.conjList (conj, list, fmt)
return stringifyList(list, {conjunction = conj, formatted = fmt})
end
-- Stringifies lists with "and" or "or"
function p.andList (...) return p.conjList("and", ...) end
function p.orList (...) return p.conjList("or", ...) end
--------------------------------------------------------------------------------
-- For see
--
-- Makes a "For X, see [[Y]]." list from raw parameters. Intended for the
-- {{about}} and {{redirect}} templates and their variants.
--------------------------------------------------------------------------------
--default options table used across the forSee family of functions
local forSeeDefaultOptions = {
andKeyword = 'and',
title = mw.title.getCurrentTitle().text,
otherText = 'other uses',
forSeeForm = 'For %s, see %s.',
}
--Collapses duplicate punctuation
local function punctuationCollapse (text)
local replacements = {
["%.%.$"] = ".",
["%?%.$"] = "?",
["%!%.$"] = "!",
["%.%]%]%.$"] = ".]]",
["%?%]%]%.$"] = "?]]",
["%!%]%]%.$"] = "!]]"
}
for k, v in pairs(replacements) do text = string.gsub(text, k, v) end
return text
end
-- Structures arguments into a table for stringification, & options
function p.forSeeArgsToTable (args, from, options)
-- Type-checks and defaults
checkType("forSeeArgsToTable", 1, args, 'table')
checkType("forSeeArgsToTable", 2, from, 'number', true)
from = from or 1
checkType("forSeeArgsToTable", 3, options, 'table', true)
options = options or {}
for k, v in pairs(forSeeDefaultOptions) do
if options[k] == nil then options[k] = v end
end
-- maxArg's gotten manually because getArgs() and table.maxn aren't friends
local maxArg = 0
for k, v in pairs(args) do
if type(k) == 'number' and k > maxArg then maxArg = k end
end
-- Structure the data out from the parameter list:
-- * forTable is the wrapper table, with forRow rows
-- * Rows are tables of a "use" string & a "pages" table of pagename strings
-- * Blanks are left empty for defaulting elsewhere, but can terminate list
local forTable = {}
local i = from
local terminated = false
-- If there is extra text, and no arguments are given, give nil value
-- to not produce default of "For other uses, see foo (disambiguation)"
if options.extratext and i > maxArg then return nil end
-- Loop to generate rows
repeat
-- New empty row
local forRow = {}
-- On blank use, assume list's ended & break at end of this loop
forRow.use = args[i]
if not args[i] then terminated = true end
-- New empty list of pages
forRow.pages = {}
-- Insert first pages item if present
table.insert(forRow.pages, args[i + 1])
-- If the param after next is "and", do inner loop to collect params
-- until the "and"'s stop. Blanks are ignored: "1|and||and|3" → {1, 3}
while args[i + 2] == options.andKeyword do
if args[i + 3] then
table.insert(forRow.pages, args[i + 3])
end
-- Increment to next "and"
i = i + 2
end
-- Increment to next use
i = i + 2
-- Append the row
table.insert(forTable, forRow)
until terminated or i > maxArg
return forTable
end
-- Stringifies a table as formatted by forSeeArgsToTable
function p.forSeeTableToString (forSeeTable, options)
-- Type-checks and defaults
checkType("forSeeTableToString", 1, forSeeTable, "table", true)
checkType("forSeeTableToString", 2, options, "table", true)
options = options or {}
for k, v in pairs(forSeeDefaultOptions) do
if options[k] == nil then options[k] = v end
end
-- Stringify each for-see item into a list
local strList = {}
if forSeeTable then
for k, v in pairs(forSeeTable) do
local useStr = v.use or options.otherText
local pagesStr =
p.andList(v.pages, true) or
mFormatLink._formatLink{
categorizeMissing = mHatnote.missingTargetCat,
link = mHatnote.disambiguate(options.title)
}
local forSeeStr = string.format(options.forSeeForm, useStr, pagesStr)
forSeeStr = punctuationCollapse(forSeeStr)
table.insert(strList, forSeeStr)
end
end
if options.extratext then table.insert(strList, punctuationCollapse(options.extratext..'.')) end
-- Return the concatenated list
return table.concat(strList, ' ')
end
-- Produces a "For X, see [[Y]]" string from arguments. Expects index gaps
-- but not blank/whitespace values. Ignores named args and args < "from".
function p._forSee (args, from, options)
local forSeeTable = p.forSeeArgsToTable(args, from, options)
return p.forSeeTableToString(forSeeTable, options)
end
-- As _forSee, but uses the frame.
function p.forSee (frame, from, options)
mArguments = require('Module:Arguments')
return p._forSee(mArguments.getArgs(frame), from, options)
end
return p
d0828422b1aa0d0d0092d699d059c9e882260398
Module:Yesno
828
51
101
100
2024-01-11T08:38:10Z
EvaTheServal
2
1 revision imported
Scribunto
text/plain
-- Imported from: https://en.wikipedia.org/wiki/Module:Yesno
-- Function allowing for consistent treatment of boolean-like wikitext input.
-- It works similarly to the template {{yesno}}.
return function (val, default)
-- If your wiki uses non-ascii characters for any of "yes", "no", etc., you
-- should replace "val:lower()" with "mw.ustring.lower(val)" in the
-- following line.
val = type(val) == 'string' and val:lower() or val
if val == nil then
return nil
elseif val == true
or val == 'yes'
or val == 'y'
or val == 'true'
or val == 't'
or val == 'on'
or val == 'ja'
or tonumber(val) == 1
then
return true
elseif val == false
or val == 'no'
or val == 'n'
or val == 'false'
or val == 'f'
or val == 'off'
or val == 'nein'
or tonumber(val) == 0
then
return false
else
return default
end
end
4cb9790f60303552aa5d331d9ab52f0a3e1f266e
Template:Documentation
10
52
103
102
2024-01-11T08:38:11Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
<includeonly>{{#invoke:Documentation|doc}}__NOEDITSECTION__{{#seo:
|type = website
|description = {{FULLPAGENAME}} is a template page used on the Star Citizen Wiki. Templates are pages that are embedded (transcluded) into other pages to allow for the repetition of information.
|site_name = Star Citizen Wiki
|locale = {{PAGELANGUAGE}}
}}</includeonly><noinclude>{{/doc}}</noinclude>
2690a5347936db4ace54fe94a0b3092b6bb04a37
Template:Documentation/styles.css
10
53
105
104
2024-01-11T08:38:12Z
EvaTheServal
2
1 revision imported
text
text/plain
.documentation {
display: flex;
box-sizing: border-box;
flex-direction: column;
margin: 1.6rem 0;
padding-top: 1.6rem;
border-top: 1px solid;
border-color: var( --border-color-base );
border-radius: var( --border-radius--medium );
font-size: 0.875rem;
}
.documentation-header {
margin-top: 0;
margin-bottom: 0.8rem;
color: var( --color-base--emphasized );
font-size: 1.25rem;
font-weight: 600;
line-height: 1.2;
}
.documentation-subheader {
margin: -0.6rem 0 1.6rem 0;
color: var( --color-base--subtle );
font-size: 0.825rem;
}
.documentation-links {
margin: 0.3rem 0;
float: right;
font-family: monospace;
font-size: 0.875rem;
font-weight: 400;
}
.documentation-modulestats {
display: flex;
align-items: center;
justify-content: space-between;
}
.documentation-modulestats .wikitable{
margin: 0;
}
/**
* Tooltip styles used by DependencyList,
* shouldn't be here but it is only used here anyways
*/
.hatnote-container {
position: relative;
}
.tooltip-trigger {
padding: 0.2rem 0.5rem;
margin-right: 2px;
background: var( --color-primary );
border-radius: 100px;
color: #fff;
}
.tooltip-trigger:hover {
background: var( --color-primary--hover );
}
.tooltip-content {
position: absolute;
z-index: 1;
right: 0;
padding: 15px;
background-color: var( --color-surface-1 );
border-radius: var( --border-radius--medium );
box-shadow: 0 14px 28px rgba( 0, 0, 0, 0.06 ), 0 10px 10px rgba( 0, 0, 0, 0.06 );
visibility: hidden;
}
.tooltip-content > ol {
margin-top: 0;
margin-left: 1.2rem;
}
.tooltip-content:hover,
.tooltip-trigger:hover + .tooltip-content {
visibility: visible;
}
7cedb77e3d7d2055318ceaf9b5e24342b73243ce
Module:DPLlua
828
54
107
106
2024-01-11T08:38:13Z
EvaTheServal
2
1 revision imported
Scribunto
text/plain
-- <nowiki>
local dpl = {}
local libraryUtil = require( 'libraryUtil' )
local hasContent = require( 'Module:Paramtest' ).has_content
local checkType = libraryUtil.checkType
local checkTypeForNamedArg = libraryUtil.checkTypeForNamedArg
dpl.pipe = '¦'
local dataContentMarker = '`#@@#`'
local allIncludedParamNames = {}
-- Custom function for splitting a string because mw.text.split() is waaay too slow
local function split( str, pattern, plain )
local res = {}
local continue = true
local startIndex = 1
while continue do
local i, j = string.find( str, pattern, startIndex, plain )
if i then
table.insert( res, string.sub( str, startIndex, i-1 ) )
startIndex = j + 1
else
table.insert( res, string.sub( str, startIndex ) )
continue = false
end
end
return res
end
-- Also custom function for speed
local function trim( str )
return (string.gsub( str, '^%s+', '' ):gsub( '%s+$', '' ))
end
local function mergeItem( tbl, key, item )
if type( tbl[key] ) == 'table' and type( item ) == 'table' then
for k in pairs( tbl[key] ) do
mergeItem( tbl[key], k, item[k] )
end
elseif type( tbl[key] ) == 'table' then
table.insert( tbl[key], item )
else
tbl[key] = { tbl[key], item }
end
end
local escapeChars = {
['{'] = '{',
['}'] = '}',
['['] = '[',
[']'] = ']',
['|'] = '|',
['-'] = '‐'
}
local function escape( str )
return (string.gsub( str, '[{}%[%]|%-]', escapeChars ))
end
local unEscapeChars = {
['{'] = '{',
['}'] = '}',
['['] = '[',
[']'] = ']',
['|'] = '|',
['‐'] = '-'
}
local function unEscape( str )
return (string.gsub( str, '&#%d+;', unEscapeChars ))
end
local function fixCurlyBrackets( str )
-- the \226\157\180\181 are used to match ❴ (U+2774) and ❵ (U+2775) wich are 3 bytes long (UTF-8) so
-- we can't use them directly inside [] patterns. Ustring would fix this but it's way too slow.
return (string.gsub( str, '\226\157[\180\181]', { ['❴'] = '{', ['❵'] = '}' } ))
end
local function removeFormattingSettings( query )
local toRemove = {
'mode',
'table',
'tablerow',
'tablesortcol',
'headingmode',
'headingcount',
'listattr',
'itemattr',
'hlistattr',
'hitemattr',
'userdateformat',
'shownamespace',
'escapelinks',
'titlemaxlength',
'replaceintitle',
'columns',
'rows',
'rowsize',
'rowcolformat',
'resultsheader',
'resultsfooter',
'oneresultheader',
'oneresultfooter',
'noresultsheader',
'suppresserrors',
'noresultsfooter',
'format',
'groupMultiTemplateResults'
}
for _, k in ipairs( toRemove ) do
query[k] = nil
end
end
local function formatInclude( query )
checkTypeForNamedArg( 'Module:DPLlua.ask', 'include', query, 'string' )
query = split( query, ',', true )
local includedParamNames = {}
local sectionAttributes = {}
for i = 1, #query do
if query[i]:match( '%b{}' ) then -- Check if we are including a template
local templateName, extra = query[i]:match( '{(.-)[¦|}](.*)' )
if hasContent( extra ) then
local phantomTemplateName = extra:match( '^(.-)}' ) or extra:match( '^[./].+' )
local phantomTemplatePrefix = extra:match( '^(.-)}' ) and '' or templateName
local params = extra:gsub( '^.-}', '' ):gsub( '^[./].+', '' ):gsub( ':%-', '' )
local sur = hasContent( phantomTemplateName ) and ('¦' .. phantomTemplatePrefix .. phantomTemplateName) or ''
query[i] = string.format( '{%s%s}%s', templateName, sur, params )
if hasContent( phantomTemplateName ) then
table.insert( includedParamNames, { name=phantomTemplatePrefix..phantomTemplateName, isTemplate=true, hasPhantomTemplate=true } )
table.insert( sectionAttributes, { hasPhantomTemplate=true } )
else
for param in params:gmatch( ':([^:]*)' ) do
param = trim( param )
table.insert( includedParamNames, { name=templateName, isTemplate=true, param=param } )
end
table.insert( sectionAttributes, { hasPhantomTemplate=false } )
end
else
query[i] = string.format( '{%s¦DPLlua helper}', templateName ) -- Use a helper template to get all the parameters of our included template
table.insert( includedParamNames, { name=templateName, isTemplate=true, includeAll=true } )
table.insert( sectionAttributes, { hasPhantomTemplate=false } )
end
else
table.insert( includedParamNames, { name=trim( query[i] ) } )
table.insert( sectionAttributes, { hasPhantomTemplate=false } )
end
end
return table.concat( query, ',' ), includedParamNames, sectionAttributes
end
local function formatDpl( query )
local queries = {}
local count = query.count or 500
local offset = query.offset or 0
local usesInclude = false
local includedParamNames = {}
local sectionAttributes
query.count = nil
query.offset = nil
-- Use table format so we can place dataContentMarkers around each included parameter. The secseparator
-- is needed to add dataContentMarkers when a phantom template is used
local dplStringInclude =
[=[
{{#dpl:
|noresultsheader=@@
|count=%s
|offset=%s
|%s
|table=,
|listseparators=,\n¦-\n¦[[%%PAGE%%¦]],,
|tablerow=%s
|secseparators=%s
}}]=]
-- Table format requires an include statement so we use format instead.
-- This is also a lot faster than adding an empty include statement
local dplStringNoInclude =
[=[
{{#dpl:
|noresultsheader=@@
|count=%s
|offset=%s
|%s
|format=,¦-¦[[%%PAGE%%¦]],,
}}]=]
-- Auto generate more than one dpl if count > 500
-- The results of these are later combined
for i = 1, math.ceil( count / 500 ) do
local params = {}
for k, v in pairs( query ) do
if k == 'include' then
v, includedParamNames, sectionAttributes = formatInclude( v )
usesInclude = true
end
if type( v ) == 'table' then
for _, x in ipairs( v ) do
table.insert( params, k .. '=' .. tostring( x ):gsub( '|', '¦' ) )
end
else
table.insert( params, k .. '=' .. tostring( v ):gsub( '|', '¦' ) )
end
end
if usesInclude then
local secseparators = ''
for _, v in ipairs( sectionAttributes ) do
if v.hasPhantomTemplate then
-- Phantom templates need this because they ignore tablerow formatting
secseparators = secseparators .. '¶¦' .. dataContentMarker .. ',' .. dataContentMarker .. ','
else
secseparators = secseparators .. '¶¦,,'
end
end
table.insert( queries, string.format(
dplStringInclude,
count > 500 and 500 or count,
offset,
table.concat( params, '\n|' ),
string.rep( dataContentMarker..'%%'..dataContentMarker..',', #includedParamNames ),
secseparators
) )
else
table.insert( queries, string.format(
dplStringNoInclude,
count > 500 and 500 or count,
offset,
table.concat( params, '\n|' )
) )
end
count = count - 500
offset = offset + 500
end
table.insert( allIncludedParamNames, includedParamNames )
return table.concat( queries )
end
local function toTable( query, groupMultiTemplateResults )
local includedParamNames = table.remove( allIncludedParamNames, 1 )
local usesInclude = #includedParamNames > 0
local res = {}
query = query:gsub( '<p>Extension:DynamicPageList .-</p>', function(item) res.error = item; return '' end )
if query:find( '^@@' ) then -- @@ is used when no result is found
return res
end
if usesInclude then
query = query:gsub( dataContentMarker..'(.-)'..dataContentMarker, escape )
end
query = trim( query )
query = split( query, '|-', true ) -- Results of the returned pages are separated by |-
for _, v in ipairs( query ) do
if hasContent( v ) and not v:find( '^@@' ) then
v = trim( v )
local title = v:match( '^|%[%[(.-)|' )
local rawDataList = v:match( '^|.-|.-|(.*)' ) -- This is everything after the title
if not usesInclude then
if title and title ~= '' then
table.insert( res, title )
end
else
-- When multiple includes are used (e.g. include={Template1},{Template2} or include={Template}:1:2) their results are separated by a pipe
rawDataList = split( rawDataList, '|', true )
local cleanedDataList = {}
for _incIndex, dataItem in ipairs( rawDataList ) do
local incIndex = ((_incIndex - 1) % #includedParamNames) + 1 -- Needed in case the same template appears multiple times on the same page
dataItem = unEscape( dataItem )
dataItem = trim( dataItem )
if includedParamNames[ incIndex ].isTemplate and includedParamNames[ incIndex ].includeAll then -- Check if we included a full template
-- When we include an entire template we use the %ARGS% parameter supplied by dpl.
-- However all | characters are repaced with §, e.g.:
-- §namelessParam
-- §param = text [[wowee§link text]]
-- §param2 = text {{something§something else}}
dataItem = dataItem:gsub( '\127\'"`UNIQ%-%-nowiki%-%x+%-QINU`"\'\127', function(item) return '<nowiki>' .. item .. '</nowiki>' end )
dataItem = mw.text.unstripNoWiki( dataItem ) -- Unstrip nowiki so we can clean their content
dataItem = fixCurlyBrackets( dataItem ) -- When using the %ARGS% dpl parameter, curly brackets are replaced with ❴ (U+2774) and ❵ (U+2775)
dataItem = dataItem:gsub( '%b{}', function(x) return x:gsub( '§', '|' ) end ) -- Restore pipe characters inside links and templates
dataItem = dataItem:gsub( '%b[]', function(x) return x:gsub( '§', '|' ) end )
dataItem = dataItem:gsub( '<nowiki>(.-)</nowiki>', function(x) return mw.getCurrentFrame():extensionTag( 'nowiki', x ) end ) -- Restrip nowiki
local _dataItem = {}
if dataItem ~= '' then
dataItem = split( dataItem:sub( 3 ), '§' ) -- The sub(3) removes the first § at the start. § is 2 bytes wide so start at index 3
for i, item in ipairs( dataItem ) do
if item:find( '=' ) then -- Check if the parameter is named or unnamed
local param, value = item:match( '^%s*(.-)%s*=%s*(.-)%s*$' )
_dataItem[ param ] = value
else
table.insert( _dataItem, trim( item ) )
end
end
end
dataItem = _dataItem
end
local dataListIndex = groupMultiTemplateResults and 1 or math.ceil( _incIndex / #includedParamNames )
if
includedParamNames[ incIndex ].isTemplate and
not includedParamNames[ incIndex ].includeAll and
not includedParamNames[ incIndex ].hasPhantomTemplate
then -- This means there was an include in the form 'include = {template}:param'
local templateName = includedParamNames[ incIndex ].name
local paramName = includedParamNames[ incIndex ].param
paramName = tonumber( paramName ) or paramName -- Keep as string if tonumber fails
cleanedDataList[ dataListIndex ] = cleanedDataList[ dataListIndex ] or {}
cleanedDataList[ dataListIndex ][ templateName ] = cleanedDataList[ dataListIndex ][ templateName ] or {}
if groupMultiTemplateResults and _incIndex > #includedParamNames then
mergeItem( cleanedDataList[ dataListIndex ][ templateName ], paramName, dataItem )
else
cleanedDataList[ dataListIndex ][ templateName ][ paramName ] = dataItem
end
else
local templateName = includedParamNames[ incIndex ].name
cleanedDataList[ dataListIndex ] = cleanedDataList[ dataListIndex ] or {}
if groupMultiTemplateResults and _incIndex > #includedParamNames then
mergeItem( cleanedDataList[ dataListIndex ], templateName, dataItem )
else
cleanedDataList[ dataListIndex ][ templateName ] = dataItem
end
end
end
if title and title ~= '' then
for _, v in ipairs( cleanedDataList ) do
table.insert( res, { title=title, include=v } )
end
end
end
end
end
return res
end
-- Accepts a series of tables each containig the settings for a dpl query.
-- Combinig multiple dpl queries yields better performance than doing them sequentially
function dpl.ask( ... )
local formatTime = os.clock()
local queries = { ... }
local wantsGrouping = {}
for i = 1, #queries do
checkType( 'Module:DPLlua.ask', i, queries[i], 'table' )
table.insert( wantsGrouping, queries[i].groupMultiTemplateResults or false )
removeFormattingSettings( queries[i] )
queries[i] = formatDpl( queries[i] )
end
formatTime = os.clock() - formatTime
local DPLtime = os.clock()
queries = table.concat( queries, '$@µ@$' )
queries = mw.getCurrentFrame():preprocess( queries )
queries = split( queries, '$@µ@$', true )
DPLtime = os.clock() - DPLtime
for i = 1, #queries do
local parseTime = os.clock()
queries[i] = toTable( queries[i], wantsGrouping[i] )
parseTime = os.clock() - parseTime
queries[i]['DPL time'] = DPLtime
queries[i]['Parse time'] = math.floor( (formatTime + parseTime) * 1e5 ) / 1e5 -- os.clock() has a resolution of 10µs
end
return unpack( queries )
end
-- function dpl.test()
-- local time = os.clock()
-- local a, b = dpl.ask({
-- namespace = 'Module',
-- linksto = 'Module:Chart data',
-- distinct = 'strict',
-- ordermethod = 'title',
-- nottitlematch = '%/doc¦%sandbox%¦Exchange/%¦Exchange historical/%¦Chart data',
-- ignorecase = 'true',
-- allowcachedresults = false
-- },{
-- namespace = 'Module',
-- linksto = 'Module:Enum',
-- distinct = 'strict',
-- ordermethod = 'title',
-- nottitlematch = '%/doc¦%sandbox%¦Exchange/%¦Exchange historical/%¦Enum',
-- ignorecase = 'true',
-- allowcachedresults = false
-- })
-- mw.logObject(a)
-- mw.logObject(b)
-- local a, b = dpl.ask({
-- namespace = 'Module',
-- linksto = 'Module:Chart data',
-- distinct = 'strict',
-- ordermethod = 'title',
-- nottitlematch = '%/doc¦%sandbox%¦Exchange/%¦Exchange historical/%¦Chart data',
-- ignorecase = 'true',
-- allowcachedresults = false
-- },{
-- namespace = '',
-- ignorecase = 'true',
-- uses = 'Template:Infobox Recipe',
-- count = 50,
-- include = '{Infobox Recipe},{Infobox Item}',
-- allowcachedresults = false
-- })
-- mw.logObject(a)
-- mw.logObject(b)
-- local a = dpl.ask{
-- namespace = '',
-- uses = 'Template:Infobox Recipe',
-- include = '{Infobox Recipe}:skill:name,{Infobox Item}:update,{Infobox Item|test}',
-- count = 50,
-- ordermethod = 'title',
-- }
-- mw.logObject(a)
-- local q = dpl.ask{
-- uses = "Template:Collections table",
-- category = "Archaeology collections",
-- -- include = "{Infobox collection}:reward,{Collections table}:1:2:3:4:5:6:7:8:9:10:11:12:13:14:15",
-- include = "{Infobox collection}:reward,{Collections table}",
-- count = 100
-- }
-- mw.logObject(q)
-- local q = dpl.ask{
-- namespace = "",
-- uses = "Template:Infobox spell",
-- notcategory = {"Removed content", "Removed spells"},
-- nottitlematch = {"Enchant Crossbow Bolt", "Storm of Armadyl"},
-- include = "{Infobox spell}",
-- }
-- mw.logObject(q)
-- local list = dpl.ask{
-- namespace = 'Template',
-- uses = 'Template:Navbox',
-- ordermethod = 'title',
-- include = '{Navbox}:gtitle1:gtitle2',
-- count = 1,
-- offset = 3
-- }
-- mw.logObject(list)
-- local list = dpl.ask{
-- namespace = 'User',
-- titlematch = 'CephHunter/Sandbox/test1',
-- include = '{User:CephHunter/Sandbox/test2|User:CephHunter/Sandbox/test3},{User:CephHunter/Sandbox/test3}:1',
-- }
-- mw.logObject(list)
-- mw.logObject(dpl.ask{
-- namespace = 'User',
-- ignorecase = 'true',
-- titlematch = 'CephHunter/Sandbox/test1',
-- include = '{User:CephHunter/Sandbox/test2}'
-- })
-- mw.logObject(dpl.ask{
-- namespace = 'Module',
-- uses = 'Template:Helper module',
-- titlematch = '%/doc',
-- nottitlematch = 'Exchange/%|Exchange historical/%|Sandbox/%',
-- ordermethod = 'title',
-- include = '{Helper module}, {Helper module}:example',
-- count = 1,
-- offset = 13
-- })
-- mw.logObject(dpl.ask{
-- namespace = 'Module',
-- titlematch = 'Chart data|Absorbative calculator',
-- nottitlematch = 'Exchange/%|Exchange historical/%|Sandbox/%|%/doc|DPLlua%',
-- ordermethod = 'title',
-- include = '%0'
-- })
-- mw.logObject(dpl.ask{
-- uses = 'Template:Collections table',
-- include = '{Collections table}',
-- count = 5
-- })
-- mw.log(os.clock()-time)
-- end
return dpl
-- </nowiki>
a4585a9ed619b57adfaa5cf8d9279da529e74df5
Module:DependencyList
828
55
109
108
2024-01-11T08:38:14Z
EvaTheServal
2
1 revision imported
Scribunto
text/plain
require("strict");
local p = {}
local libraryUtil = require( 'libraryUtil' )
local arr = require( 'Module:Array' )
local yn = require( 'Module:Yesno' )
local param = require( 'Module:Paramtest' )
local dpl = require( 'Module:DPLlua' )
local userError = require("Module:User error")
local mHatnote = require('Module:Hatnote')
local mHatlist = require('Module:Hatnote list')
local moduleIsUsed = false
local COLLAPSE_LIST_LENGTH_THRESHOLD = 1
local MAX_DYNAMIC_REQUIRE_LIST_LENGTH = 30
local dynamicRequireListQueryCache = {}
local builtins = {
--[[
["libraryUtil"] = {
link = "mw:Special:MyLanguage/Extension:Scribunto/Lua reference manual#libraryUtil",
categories = {},
}
]]
["strict"] = {
link = "mw:Special:MyLanguage/Extension:Scribunto/Lua reference manual#strict",
categories = { "Strict mode modules" },
},
};
--- Used in case 'require( varName )' is found. Attempts to find a string value stored in 'varName'.
---@param content string The content of the module to search in
---@param varName string
---@return string
local function substVarValue( content, varName )
local res = content:match( varName .. '%s*=%s*(%b""%s-%.*)' ) or content:match( varName .. "%s*=%s*(%b''%s-%.*)" ) or ''
if res:find( '^(["\'])[Mm]odule:[%S]+%1' ) and not res:find( '%.%.' ) and not res:find( '%%%a' ) then
return mw.text.trim( res )
else
return ''
end
end
---@param capture string
---@param content string The content of the module to search in
---@return string
local function extractModuleName( capture, content )
capture = capture:gsub( '^%(%s*(.-)%s*%)$', '%1' )
if capture:find( '^(["\']).-%1$' ) then -- Check if it is already a pure string
return capture
elseif capture:find( '^[%a_][%w_]*$' ) then -- Check if if is a single variable
return substVarValue( content, capture )
end
return capture
end
---@param str string
---@return string
local function formatPageName( str )
local name = mw.text.trim(str)
:gsub( '^([\'\"])(.-)%1$', function(_, x) return x end ) -- Only remove quotes at start and end of string if both are the same type
:gsub( '_', ' ' )
:gsub( '^.', string.upper )
:gsub( ':.', string.upper )
return name
end
---@param str string
---@return string
local function formatModuleName( str, allowBuiltins )
if allowBuiltins then
local name = mw.text.trim(str)
-- Only remove quotes at start and end of string if both are the same type
:gsub([[^(['"])(.-)%1$]], function(_, x) return x end);
local builtin = builtins[name];
if builtin then
return builtin.link .. "|" .. name, builtin;
end
end
local module = formatPageName( str )
if not string.find( module, '^[Mm]odule:' ) then
module = 'Module:' .. module
end
return module
end
local function dualGmatch( str, pat1, pat2 )
local f1 = string.gmatch( str, pat1 )
local f2 = string.gmatch( str, pat2 )
return function()
return f1() or f2()
end
end
--- Used in case a construct like 'require( "Module:wowee/" .. isTheBest )' is found.
--- Will return a list of pages which satisfy this pattern where 'isTheBest' can take any value.
---@param query string
---@return string[] Sequence of strings
local function getDynamicRequireList( query )
local isDynamic = true;
if query:find( '%.%.' ) then
query = mw.text.split( query, '..', true )
query = arr.map( query, function(x) return mw.text.trim(x) end )
query = arr.map( query, function(x) return (x:match('^[\'\"](.-)[\'\"]$') or '%') end )
query = table.concat( query )
else
local _; _, query = query:match( '(["\'])(.-)%1' )
if query == nil then
return {}, isDynamic
end
local replacements;
query, replacements = query:gsub( '%%%a', '%%' )
if replacements == 0 then
isDynamic = false;
end
end
query = query:gsub( '^[Mm]odule:', '' )
if query:find( '^[Dd]ata/' ) then
return { 'Module:' .. query }, isDynamic; -- This format will later be used by formatDynamicQueryLink()
end
if dynamicRequireListQueryCache[ query ] then
return dynamicRequireListQueryCache[ query ], isDynamic;
end
local list = dpl.ask{
namespace = 'Module',
titlematch = query,
nottitlematch = '%/doc|'..query..'/%',
distinct = 'strict',
ignorecase = true,
ordermethod = 'title',
count = MAX_DYNAMIC_REQUIRE_LIST_LENGTH + 1,
skipthispage = 'no',
allowcachedresults = true,
cacheperiod = 604800 -- One week
}
if #list > MAX_DYNAMIC_REQUIRE_LIST_LENGTH then
list = { 'Module:' .. query }
end
dynamicRequireListQueryCache[ query ] = list
return list, isDynamic;
end
--- Returns a list of modules loaded and required by module 'moduleName'.
---@param moduleName string
---@param searchForUsedTemplates boolean
---@return string[], string[], string[], string[]
local function getRequireList( moduleName, searchForUsedTemplates )
local content = mw.title.new( moduleName ):getContent()
local requireList = arr{}
local loadDataList = arr{}
local usedTemplateList = arr{}
local dynamicRequirelist = arr{}
local dynamicLoadDataList = arr{}
local extraCategories = arr{}
assert( content ~= nil, string.format( '%s does not exist', moduleName ) )
content = content:gsub( '%-%-%[(=-)%[.-%]%1%]', '' ):gsub( '%-%-[^\n]*', '' ) -- Strip comments
for match in dualGmatch( content, 'require%s*(%b())', 'require%s*((["\'])%s*[Mm]odule:.-%2)' ) do
match = mw.text.trim( match )
match = extractModuleName( match, content )
if match:find( '%.%.' ) or match:find( '%%%a' ) then
for _, x in ipairs( getDynamicRequireList( match ) ) do
table.insert( dynamicRequirelist, x )
end
elseif match ~= '' then
local builtin;
match, builtin = formatModuleName( match, true )
table.insert( requireList, match )
if builtin then
local builtinCategories = builtin.categories;
if type(builtinCategories) == "table" then
for _, x in ipairs(builtinCategories) do
table.insert(extraCategories, x);
end
end
end
end
end
for match in dualGmatch( content, 'mw%.loadData%s*(%b())', 'mw%.loadData%s*((["\'])%s*[Mm]odule:.-%2)' ) do
match = mw.text.trim( match )
match = extractModuleName( match, content )
if match:find( '%.%.' ) or match:find( '%%%a' ) then
for _, x in ipairs( getDynamicRequireList( match ) ) do
table.insert( dynamicLoadDataList, x )
end
elseif match ~= '' then
match = formatModuleName( match, true )
table.insert( loadDataList, match )
end
end
for match in dualGmatch( content, 'mw%.loadJsonData%s*(%b())', 'mw%.loadJsonData%s*((["\'])%s*[Mm]odule:.-%2)' ) do
match = mw.text.trim( match )
match = extractModuleName( match, content )
if match:find( '%.%.' ) or match:find( '%%%a' ) then
for _, x in ipairs( getDynamicRequireList( match ) ) do
table.insert( dynamicLoadDataList, x )
end
elseif match ~= '' then
match = formatModuleName( match, true )
table.insert( loadDataList, match )
end
end
for func, match in string.gmatch( content, 'pcall%s*%(([^,]+),([^%),]+)' ) do
func = mw.text.trim( func )
match = mw.text.trim( match )
local dynList, isDynamic;
if func == 'require' then
dynList, isDynamic = getDynamicRequireList(match);
if (isDynamic == false and #dynList == 1) then
table.insert(requireList, dynList[1]);
else for _, x in ipairs(dynList) do
table.insert( dynamicRequirelist, x )
end end
elseif func == 'mw.loadData' then
dynList, isDynamic = getDynamicRequireList(match);
if (isDynamic == false and #dynList == 1) then
table.insert(loadDataList, dynList[1]);
else for _, x in ipairs(dynList) do
table.insert( dynamicLoadDataList, x )
end end
end
end
if searchForUsedTemplates then
for preprocess in string.gmatch( content, ':preprocess%s*(%b())' ) do
local function recursiveGMatch( str, pat )
local list = {}
local i = 0
repeat
for match in string.gmatch( list[i] or str, pat ) do
table.insert( list, match )
end
i = i + 1
until i > #list or i > 100
i = 0
return function()
i = i + 1
return list[i]
end
end
for template in recursiveGMatch( preprocess, '{(%b{})}' ) do
local name = string.match( template, '{(.-)[|{}]' )
if name ~= '' then
if name:find( ':' ) then
local ns = name:match( '^(.-):' )
if arr.contains( {'', 'template', 'user'}, ns:lower() ) then
table.insert( usedTemplateList, name )
elseif ns == ns:upper() then
table.insert( usedTemplateList, ns ) -- Probably a magic word
end
else
if name:match( '^%u+$' ) or name == '!' then
table.insert( usedTemplateList, name ) -- Probably a magic word
else
table.insert( usedTemplateList, 'Template:'..name )
end
end
end
end
end
end
requireList = requireList .. dynamicRequirelist:reject( loadDataList )
requireList = requireList:unique()
loadDataList = loadDataList .. dynamicLoadDataList:reject( requireList )
loadDataList = loadDataList:unique()
usedTemplateList = usedTemplateList:unique()
extraCategories = extraCategories:unique()
table.sort( requireList )
table.sort( loadDataList )
table.sort( usedTemplateList )
table.sort( extraCategories )
return requireList, loadDataList, usedTemplateList, extraCategories
end
--- Returns a list with module and function names used in all '{{#Invoke:moduleName|funcName}}' found on page 'templateName'.
---@param templateName string
---@return table<string, string>[]
local function getInvokeCallList( templateName )
local content = mw.title.new( templateName ):getContent()
local invokeList = {}
assert( content ~= nil, string.format( '%s does not exist', templateName ) )
for moduleName, funcName in string.gmatch( content, '{{[{|safeubt:}]-#[Ii]nvoke:([^|]+)|([^}|]+)[^}]*}}' ) do
moduleName = formatModuleName( moduleName )
funcName = mw.text.trim( funcName )
if string.find( funcName, '^{{{' ) then
funcName = funcName .. '}}}'
end
table.insert( invokeList, {moduleName=moduleName, funcName=funcName} )
end
invokeList = arr.unique( invokeList, function(x) return x.moduleName..x.funcName end )
table.sort( invokeList, function(x, y) return x.moduleName..x.funcName < y.moduleName..y.funcName end )
return invokeList
end
---@param pageName string
---@param addCategories boolean
---@return string
local function messageBoxUnused( pageName, addCategories )
local mbox = require( 'Module:Mbox' )._mbox
local category = addCategories and '[[Category:Unused modules]]' or ''
return mbox(
'This module is unused.',
string.format( 'This module is neither invoked by a template nor required/loaded by another module. If this is in error, make sure to add <code>{{[[Template:Documentation|Documentation]]}}</code>/<code>{{[[Template:No documentation|No documentation]]}}</code> to the calling template\'s or parent\'s module documentation.',
pageName
),
{ icon = 'WikimediaUI-Alert.svg' }
) .. category
end
local function collapseList( list, id, listType )
local text = string.format( '%d %s', #list, listType )
local button = '<span>' .. text .. ':</span> '
local content = mHatlist.andList( list, false )
return { tostring( button ) .. tostring( content ) }
end
--- Creates a link to [[Special:Search]] showing all pages found by getDynamicRequireList() in case it found more than MAX_DYNAMIC_REQUIRE_LIST_LENGTH pages.
---@param query string @This will be in a format like 'Module:Wowee/%' or 'Module:Wowee/%/data'
---@return string
local function formatDynamicQueryLink( query )
local prefix = query:match( '^([^/]+)' )
local linkText = query:gsub( '%%', '< ... >' )
query = query:gsub( '^Module:', '' )
query = query:gsub( '([^/]+)/?', function ( match )
if match == '%' then
return '\\/[^\\/]+'
else
return '\\/"' .. match .. '"'
end
end )
query = query:gsub( '^\\/', '' )
query = string.format(
'intitle:/%s%s/i -intitle:/%s\\/""/i -intitle:doc prefix:"%s"',
query,
query:find( '"$' ) and '' or '""',
query,
prefix
)
return string.format( '<span class="plainlinks">[%s %s]</span>', tostring( mw.uri.fullUrl( 'Special:Search', { search = query } ) ), linkText )
end
---@param templateName string
---@param addCategories boolean
---@param invokeList table<string, string>[] @This is the list returned by getInvokeCallList()
---@return string
local function formatInvokeCallList( templateName, addCategories, invokeList )
local category = addCategories and '[[Category:Lua-based templates]]' or ''
local res = {}
for _, item in ipairs( invokeList ) do
local msg = string.format(
"'''%s''' invokes function '''%s''' in [[%s]] using [[Star Citizen:Lua|Lua]].",
templateName,
item.funcName,
item.moduleName
)
table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) )
end
if #invokeList > 0 then
table.insert( res, category )
end
return table.concat( res )
end
---@param moduleName string
---@param addCategories boolean
---@param whatLinksHere string @A list generated by a dpl of pages in the Template namespace which link to moduleName.
---@return string
local function formatInvokedByList( moduleName, addCategories, whatLinksHere )
local function lcfirst( str )
return string.gsub( str, '^[Mm]odule:.', string.lower )
end
local templateData = arr.map( whatLinksHere, function(x) return {templateName=x, invokeList=getInvokeCallList(x)} end )
templateData = arr.filter( templateData, function(x)
return arr.any( x.invokeList, function(y)
return lcfirst(y.moduleName) == lcfirst(moduleName)
end )
end )
local invokedByList = {}
for _, template in ipairs( templateData ) do
for _, invoke in ipairs( template.invokeList ) do
table.insert( invokedByList, string.format( "function '''%s''' is invoked by [[%s]]", invoke.funcName, template.templateName ) )
end
end
table.sort( invokedByList)
local res = {}
if #invokedByList > COLLAPSE_LIST_LENGTH_THRESHOLD then
local msg = string.format(
"'''%s''' is invoked by %s.",
moduleName,
collapseList( invokedByList, 'invokedBy', 'templates' )[1]
)
table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) )
else
for _, item in ipairs( invokedByList ) do
local msg = string.format(
"'''%s's''' %s.",
moduleName,
item
)
table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) )
end
end
if #templateData > 0 then
moduleIsUsed = true
table.insert( res, (addCategories and '[[Category:Template invoked modules]]' or '') )
end
return table.concat( res )
end
---@param moduleName string
---@param addCategories boolean
---@param whatLinksHere string @A list generated by a dpl of pages in the Module namespace which link to moduleName.
---@return string
local function formatRequiredByList( moduleName, addCategories, whatLinksHere )
local childModuleData = arr.map( whatLinksHere, function ( title )
local requireList, loadDataList = getRequireList( title )
return {name=title, requireList=requireList, loadDataList=loadDataList}
end )
local requiredByList = arr.map( childModuleData, function ( item )
if arr.any( item.requireList, function(x) return x:lower()==moduleName:lower() end ) then
if item.name:find( '%%' ) then
return formatDynamicQueryLink( item.name )
else
return '[[' .. item.name .. ']]'
end
end
end )
local loadedByList = arr.map( childModuleData, function ( item )
if arr.any( item.loadDataList, function(x) return x:lower()==moduleName:lower() end ) then
if item.name:find( '%%' ) then
return formatDynamicQueryLink( item.name )
else
return '[[' .. item.name .. ']]'
end
end
end )
if #requiredByList > 0 or #loadedByList > 0 then
moduleIsUsed = true
end
if #requiredByList > COLLAPSE_LIST_LENGTH_THRESHOLD then
requiredByList = collapseList( requiredByList, 'requiredBy', 'modules' )
end
if #loadedByList > COLLAPSE_LIST_LENGTH_THRESHOLD then
loadedByList = collapseList( loadedByList, 'loadedBy', 'modules' )
end
local res = {}
for _, requiredByModuleName in ipairs( requiredByList ) do
local msg = string.format(
"'''%s''' is required by %s.",
moduleName,
requiredByModuleName
)
table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) )
end
if #requiredByList > 0 then
table.insert( res, (addCategories and '[[Category:Modules required by modules]]' or '') )
end
for _, loadedByModuleName in ipairs( loadedByList ) do
local msg = string.format(
"'''%s''' is loaded by %s.",
moduleName,
requiredByModuleName
)
table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) )
end
if #loadedByList > 0 then
table.insert( res, (addCategories and '[[Category:Module data]]' or '') )
end
return table.concat( res )
end
local function formatRequireList( currentPageName, addCategories, requireList )
local res = {}
if #requireList > COLLAPSE_LIST_LENGTH_THRESHOLD then
requireList = collapseList( requireList, 'require', 'modules' )
end
for _, requiredModuleName in ipairs( requireList ) do
local msg = string.format(
"'''%s''' requires %s.",
currentPageName,
requiredModuleName
)
table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) )
end
if #requireList > 0 then
table.insert( res, (addCategories and '[[Category:Modules requiring modules]]' or '') )
end
return table.concat( res )
end
local function formatLoadDataList( currentPageName, addCategories, loadDataList )
local res = {}
if #loadDataList > COLLAPSE_LIST_LENGTH_THRESHOLD then
loadDataList = collapseList( loadDataList, 'loadData', 'modules' )
end
for _, loadedModuleName in ipairs( loadDataList ) do
local msg = string.format(
"'''%s''' loads data from %s.",
currentPageName,
loadedModuleName
)
table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) )
end
if #loadDataList > 0 then
table.insert( res, (addCategories and '[[Category:Modules using data]]' or '') )
end
return table.concat( res )
end
local function formatUsedTemplatesList( currentPageName, addCategories, usedTemplateList )
local res = {}
if #usedTemplateList > COLLAPSE_LIST_LENGTH_THRESHOLD then
usedTemplateList = collapseList( usedTemplateList, 'usedTemplates', 'templates' )
end
for _, templateName in ipairs( usedTemplateList ) do
local msg = string.format(
"'''%s''' transcludes [[%s]] using <samp>frame:preprocess()</samp>.",
currentPageName,
templateName
)
table.insert( res, mHatnote._hatnote( msg, { icon='WikimediaUI-Code.svg' } ) )
end
return table.concat( res )
end
function p.main( frame )
local args = frame:getParent().args
return p._main( args[1], args.category, args.isUsed )
end
---@param currentPageName string|nil
---@param addCategories boolean|string|nil
---@return string
function p._main( currentPageName, addCategories, isUsed )
libraryUtil.checkType( 'Module:RequireList._main', 1, currentPageName, 'string', true )
libraryUtil.checkTypeMulti( 'Module:RequireList._main', 2, addCategories, {'boolean', 'string', 'nil'} )
libraryUtil.checkTypeMulti( 'Module:RequireList._main', 3, isUsed, {'boolean', 'string', 'nil'} )
local title = mw.title.getCurrentTitle()
-- Leave early if not in module or template namespace
if param.is_empty( currentPageName ) and
( not arr.contains( {'Module', 'Template'}, title.nsText ) ) then
return ''
end
currentPageName = param.default_to( currentPageName, title.fullText )
currentPageName = string.gsub( currentPageName, '/[Dd]oc$', '' )
currentPageName = formatPageName( currentPageName )
addCategories = yn( param.default_to( addCategories, title.subpageText~='doc' ) )
moduleIsUsed = yn( param.default_to( isUsed, false ) )
if title.text:lower():find( 'sandbox' ) then
moduleIsUsed = true -- Don't show sandbox modules as unused
end
if currentPageName:find( '^Template:' ) then
local ok, invokeList = pcall( getInvokeCallList, currentPageName )
if ok then
return formatInvokeCallList( currentPageName, addCategories, invokeList )
else
return userError(invokeList)
end
end
local whatTemplatesLinkHere, whatModulesLinkHere = dpl.ask( {
namespace = 'Template',
linksto = currentPageName,
distinct = 'strict',
ignorecase = true,
ordermethod = 'title',
allowcachedresults = true,
cacheperiod = 604800 -- One week
}, {
namespace = 'Module',
linksto = currentPageName,
nottitlematch = '%/doc%|' .. currentPageName:gsub( 'Module:', '' ),
distinct = 'strict',
ignorecase = true,
ordermethod = 'title',
allowcachedresults = true,
cacheperiod = 604800 -- One week
} )
local requireList, loadDataList, usedTemplateList, extraCategories;
do
local ok;
ok, requireList, loadDataList, usedTemplateList, extraCategories = pcall(getRequireList, currentPageName, true);
if not ok then
return userError(requireList);
end
end
requireList = arr.map( requireList, function ( moduleName )
if moduleName:find( '%%' ) then
return formatDynamicQueryLink( moduleName )
else
return '[[' .. moduleName .. ']]'
end
end )
loadDataList = arr.map( loadDataList, function ( moduleName )
if moduleName:find( '%%' ) then
return formatDynamicQueryLink( moduleName )
else
return '[[' .. moduleName .. ']]'
end
end )
usedTemplateList = arr.map( usedTemplateList, function( templateName )
if string.find( templateName, ':' ) then -- Real templates are prefixed by a namespace, magic words are not
return '[['..templateName..']]'
else
return "'''{{"..templateName.."}}'''" -- Magic words don't have a page so make them bold instead
end
end )
local res = {}
table.insert( res, formatInvokedByList( currentPageName, addCategories, whatTemplatesLinkHere ) )
table.insert( res, formatRequireList( currentPageName, addCategories, requireList ) )
table.insert( res, formatLoadDataList( currentPageName, addCategories, loadDataList ) )
table.insert( res, formatUsedTemplatesList( currentPageName, addCategories, usedTemplateList ) )
table.insert( res, formatRequiredByList( currentPageName, addCategories, whatModulesLinkHere ) )
if addCategories then
extraCategories = arr.map(extraCategories, function(categoryName)
return "[[Category:" .. categoryName .. "]]";
end);
table.insert(res, table.concat(extraCategories));
end
if not moduleIsUsed then
table.insert( res, 1, messageBoxUnused( currentPageName:gsub( 'Module:', '' ), addCategories ) )
end
return table.concat( res )
end
return p
-- </nowiki>
d5f03ab1075172cdbb69e217ef5ed86f0d973480
Module:Documentation
828
56
111
110
2024-01-11T08:38:15Z
EvaTheServal
2
1 revision imported
Scribunto
text/plain
-- <nowiki>
local dependencyList = require( 'Module:DependencyList' )
local yn = require( 'Module:Yesno' )
local hatnote = require( 'Module:Hatnote' )._hatnote
local mbox = require( 'Module:Mbox' )._mbox
local lang = mw.getContentLanguage()
local p = {}
function p.doc( frame )
local title = mw.title.getCurrentTitle()
local args = frame:getParent().args
local page = args[1] or mw.ustring.gsub( title.fullText, '/doc$', '' )
local ret, cats, ret1, ret2, ret3
local pageType = title.namespace == 828 and 'module' or 'template'
local opts = frame.args;
-- subpage header
if title.subpageText == 'doc' then
ret = mbox(
'This is a documentation subpage for ' .. page .. '.',
string.format(
'It contains usage information, categories, and other content that is not part of the [[' .. page .. '|original %s page]].',
pageType
),
{ icon = 'WikimediaUI-Notice.svg' }
)
if title.namespace == 10 then -- Template namespace
cats = '[[Category:Template documentation|' .. title.baseText .. ']]'
ret2 = dependencyList._main()
elseif title.namespace == 828 then -- Module namespace
cats = '[[Category:Module documentation|' .. title.baseText .. ']]'
ret2 = dependencyList._main()
ret2 = ret2 .. require('Module:Module toc').main()
else
cats = ''
ret2 = ''
end
return tostring( ret ) .. ret2 .. cats
end
-- template header
-- don't use mw.html as we aren't closing the main div tag
ret1 = '<div class="documentation">'
ret2 = mw.html.create( nil )
:tag( 'div' )
:addClass( 'documentation-header' )
:tag( 'span' )
:addClass( 'documentation-title' )
:wikitext( lang:ucfirst( string.format('%s documentation', pageType) ) )
:done()
:tag( 'span' )
:addClass( 'documentation-links plainlinks' )
:wikitext(
'[[' .. tostring( mw.uri.fullUrl( page .. '/doc', {action='view'} ) ) .. ' view]]' ..
'[[' .. tostring( mw.uri.fullUrl( page .. '/doc', {action='edit'} ) ) .. ' edit]]' ..
'[[' .. tostring( mw.uri.fullUrl( page .. '/doc', {action='history'} ) ) .. ' history]]' ..
'[<span class="jsPurgeLink">[' .. tostring( mw.uri.fullUrl( title.fullText, {action='purge'} ) ) .. ' purge]</span>]'
)
:done()
:done()
:tag( 'div' )
:addClass( 'documentation-subheader' )
:tag( 'span' )
:addClass( 'documentation-documentation' )
:wikitext( 'This documentation is transcluded from [[' .. page .. '/doc]]. Changes can be proposed in the talk page.' )
:done()
:wikitext(frame:extensionTag{ name = 'templatestyles', args = { src = 'Documentation/styles.css'} })
:done()
ret3 = {}
if args.scwShared then
--- Message box
table.insert( ret3,
mbox(
string.format(
"'''%s''' is [%s%s shared across] the Star Citizen Wikis.",
title.fullText,
'https://github.com/The-Star-Citizen-Wikis/SharedModules/tree/master/',
mw.uri.encode( title.rootText, 'PATH' )
),
string.format(
'This %s is shared across the Star Citizen Wikis. Any changes should also be relayed to the GitHub repository.',
pageType
),
{ icon = 'WikimediaUI-ArticleDisambiguation-ltr.svg' }
)
)
--- Set category
table.insert( ret3, string.format( '[[Category:%s shared by the Star Citizen Wikis]]', lang:ucfirst( pageType ) .. 's' ) )
--- Interlanguage link
--- TODO: Make this into a for loop when there are more wikis
table.insert( ret3, string.format( '[[%s:%s]]', 'de', title.fullText ) )
end
if args.fromWikipedia then
table.insert( ret3,
mbox(
string.format(
"'''%s''' is imported from [https://en.wikipedia.org/wiki/%s %s] on Wikipedia.",
title.fullText,
page,
page
),
string.format(
'This %s is imported from the English Wikipedia. Although the visual appearance might be different, the functionality is identical. Please refer to the Wikipedia page for detailed documentation.',
pageType
),
{ icon = 'WikimediaUI-Logo-Wikipedia.svg' }
)
)
--- Set category
table.insert( ret3, string.format( '[[Category:%s imported from Wikipedia]]', lang:ucfirst( pageType ) .. 's' ) )
end
if title.namespace == 828 then
-- Has config
if mw.title.new( title.fullText .. '/config.json', 'Module' ).exists then
table.insert( ret3,
mbox(
string.format(
"'''%s''' loads configuration from [[%s/config.json]].",
title.fullText,
title.fullText
),
'This module can be configurated from the config.json subpage.',
{ icon='WikimediaUI-Settings.svg' }
)
)
end
-- Has localization
if mw.title.new( title.fullText .. '/i18n.json', 'Module' ).exists then
table.insert( ret3,
mbox(
string.format(
"'''%s''' loads messages from [[%s/i18n.json]].",
title.fullText,
title.fullText
),
'This module is designed to be language-neutral. All of the messages are saved in the i18n.json subpage.',
{ icon='WikimediaUI-Language.svg' }
)
)
end
-- Testcase page
if title.subpageText == 'testcases' then
table.insert( ret3,
hatnote(
string.format( 'This is the test cases page for the module [[Module:%s]].', title.baseText ),
{ icon='WikimediaUI-LabFlask.svg' }
)
)
end
end
--- Dependency list
table.insert( ret3, dependencyList._main( nil, args.category, args.isUsed ) )
-- Has templatestyles
if mw.title.new( title.fullText .. '/styles.css' ).exists then
table.insert( ret3,
hatnote(
string.format(
"'''%s''' loads styles from [[%s/styles.css]].",
title.fullText,
title.fullText
),
{ icon='WikimediaUI-Palette.svg' }
)
)
end
--- Module stats bar
if title.namespace == 828 then
table.insert( ret3, '<div class="documentation-modulestats">' )
-- Function list
table.insert( ret3, require( 'Module:Module toc' ).main() )
-- Unit tests
local testcaseTitle = title.baseText .. '/testcases'
if mw.title.new( testcaseTitle, 'Module' ).exists then
-- There is probably a better way :P
table.insert( ret3, frame:preprocess( '{{#invoke:' .. testcaseTitle .. '|run}}' ) )
end
table.insert( ret3, '</div>' )
end
return ret1 .. tostring( ret2 ) .. '<div class="documentation-content">' .. table.concat( ret3 )
end
return p
-- </nowiki>
5a5b6781058f69e3613197f6be6173d07d2bf085
Module:Paramtest
828
57
113
112
2024-01-11T08:38:17Z
EvaTheServal
2
1 revision imported
Scribunto
text/plain
-- Imported from: https://runescape.wiki/w/Module:Paramtest
--[[
{{Helper module
|name=Paramtest
|fname1 = is_empty(arg)
|ftype1 = String
|fuse1 = Returns true if arg is not defined or contains only whitespace
|fname2 = has_content(arg)
|ftype2 = String
|fuse2 = Returns true if arg exists and does not only contain whitespace
|fname3 = default_to(arg1,arg2)
|ftype3 = String, Any value
|fuse3 = If arg1 exists and does not only contain whitespace, the function returns arg1, otherwise returns arg2
|fname4 = defaults{ {arg1,arg2},...}
|ftype4 = {String, Any value}...
|fuse4 = Does the same as <code>default_to()</code> run over every table passed
|fname5 = table_is_empty(arg)
|ftype5 = Table
|fuse5 = Returns true if the table has no content, it does not check if the content of the table contains anything
|fname6 = table_has_content(arg)
|ftype6 = Table
|fuse6 = returns true if the table has content, it does not check if the content of the table contains anything
}}
--]]
local checkType, checkTypeForNamedArg
do
local _libraryUtil = require("libraryUtil");
checkType = _libraryUtil.checkType;
checkTypeForNamedArg = _libraryUtil.checkTypeForNamedArg;
end
--
-- Tests basic properties of parameters
--
local p = {}
--
-- Tests if the parameter is empty, all white space, or undefined
--
function p.is_empty(arg)
return not string.find(arg or '', '%S')
end
--
-- Tests if the table parameter is empty
--
function p.table_is_empty(arg)
for _, _ in pairs(arg) do
return false
end
return true
end
--
-- Returns the parameter if it has any content, the default (2nd param)
--
function p.default_to(arg, default)
if string.find(arg or '', '%S') then
return arg
else
return default
end
end
--
-- Returns a list of paramaters if it has any content, or the default
--
function p.defaults(args)
checkType("defaults", 1, args, "table");
local ret = {}
for i, v in ipairs(args) do
checkTypeForNamedArg("defaults", i, v, "table");
ret[i] = p.default_to(v[1], v[2]);
end
return unpack(ret, 1, #args);
end
--
-- Tests if the parameter has content
-- The same as !is_empty, but this is more readily clear
--
function p.has_content(arg)
return string.find(arg or '', '%S')
end
--
-- Tests if the table parameter has content
-- The same as !table_is_empty, but this is more readily clear
--
function p.table_has_content(arg)
for _, _ in pairs(arg) do
return true
end
return false
end
--
-- uppercases first letter
--
function p.ucfirst(arg)
if not arg or arg:len() == 0 then
return nil
elseif arg:len() == 1 then
return arg:upper()
else
return arg:sub(1,1):upper() .. arg:sub(2)
end
end
--
-- uppercases first letter, lowercases everything else
--
function p.ucflc(arg)
if not arg or arg:len() == 0 then
return nil
elseif arg:len() == 1 then
return arg:upper()
else
return arg:sub(1,1):upper() .. arg:sub(2):lower()
end
end
return p
d69422a8379e1fcb190fe16e6d212071b9caa1dc
Module:Infobox
828
58
115
114
2024-01-11T08:38:19Z
EvaTheServal
2
1 revision imported
Scribunto
text/plain
--
-- This module implements {{Infobox}}
--
local p = {}
-- local navbar = require('Module:Navbar')._navbar
local args = {}
local origArgs
local root
local function notempty( s ) return s and s:match( '%S' ) end
local function fixChildBoxes(sval, tt)
if notempty(sval) then
local marker = '<span class=special_infobox_marker>'
local s = sval
s = mw.ustring.gsub(s, '(<%s*[Tt][Rr])', marker .. '%1')
s = mw.ustring.gsub(s, '(</[Tt][Rr]%s*>)', '%1' .. marker)
if s:match(marker) then
s = mw.ustring.gsub(s, marker .. '%s*' .. marker, '')
s = mw.ustring.gsub(s, '([\r\n]|-[^\r\n]*[\r\n])%s*' .. marker, '%1')
s = mw.ustring.gsub(s, marker .. '%s*([\r\n]|-)', '%1')
s = mw.ustring.gsub(s, '(</[Cc][Aa][Pp][Tt][Ii][Oo][Nn]%s*>%s*)' .. marker, '%1')
s = mw.ustring.gsub(s, '(<%s*[Tt][Aa][Bb][Ll][Ee][^<>]*>%s*)' .. marker, '%1')
s = mw.ustring.gsub(s, '^(%{|[^\r\n]*[\r\n]%s*)' .. marker, '%1')
s = mw.ustring.gsub(s, '([\r\n]%{|[^\r\n]*[\r\n]%s*)' .. marker, '%1')
s = mw.ustring.gsub(s, marker .. '(%s*</[Tt][Aa][Bb][Ll][Ee]%s*>)', '%1')
s = mw.ustring.gsub(s, marker .. '(%s*\n|%})', '%1')
end
if s:match(marker) then
local subcells = mw.text.split(s, marker)
s = ''
for k = 1, #subcells do
if k == 1 then
s = s .. subcells[k] .. '</' .. tt .. '></tr>'
elseif k == #subcells then
local rowstyle = ' style="display:none"'
if notempty(subcells[k]) then rowstyle = '' end
s = s .. '<tr' .. rowstyle ..'><' .. tt .. ' colspan=2>\n' .. subcells[k]
elseif notempty(subcells[k]) then
if (k % 2) == 0 then
s = s .. subcells[k]
else
s = s .. '<tr><' .. tt .. ' colspan=2>\n' .. subcells[k] .. '</' .. tt .. '></tr>'
end
end
end
end
-- the next two lines add a newline at the end of lists for the PHP parser
-- https://en.wikipedia.org/w/index.php?title=Template_talk:Infobox_musical_artist&oldid=849054481
-- remove when [[:phab:T191516]] is fixed or OBE
s = mw.ustring.gsub(s, '([\r\n][%*#;:][^\r\n]*)$', '%1\n')
s = mw.ustring.gsub(s, '^([%*#;:][^\r\n]*)$', '%1\n')
s = mw.ustring.gsub(s, '^([%*#;:])', '\n%1')
s = mw.ustring.gsub(s, '^(%{%|)', '\n%1')
return s
else
return sval
end
end
local function union(t1, t2)
-- Returns the union of the values of two tables, as a sequence.
local vals = {}
for k, v in pairs(t1) do
vals[v] = true
end
for k, v in pairs(t2) do
vals[v] = true
end
local ret = {}
for k, v in pairs(vals) do
table.insert(ret, k)
end
return ret
end
local function getArgNums(prefix)
-- Returns a table containing the numbers of the arguments that exist
-- for the specified prefix. For example, if the prefix was 'data', and
-- 'data1', 'data2', and 'data5' exist, it would return {1, 2, 5}.
local nums = {}
for k, v in pairs(args) do
local num = tostring(k):match('^' .. prefix .. '([1-9]%d*)$')
if num then table.insert(nums, tonumber(num)) end
end
table.sort(nums)
return nums
end
local function addRow(rowArgs)
-- Adds a row to the infobox, with either a header cell
-- or a label/data cell combination.
if rowArgs.header then
root
:tag('tr')
:addClass(rowArgs.rowclass)
:cssText(rowArgs.rowstyle)
:attr('id', rowArgs.rowid)
:tag('th')
:attr('colspan', 2)
:attr('id', rowArgs.headerid)
:addClass(rowArgs.class)
:addClass(args.headerclass)
----:css('text-align', 'center')
:cssText(args.headerstyle)
:cssText(rowArgs.rowcellstyle)
:wikitext(fixChildBoxes(rowArgs.header, 'th'))
elseif rowArgs.data then
local row = root:tag('tr')
row:addClass(rowArgs.rowclass)
row:cssText(rowArgs.rowstyle)
row:attr('id', rowArgs.rowid)
if rowArgs.label then
row
:tag('th')
:attr('scope', 'row')
:attr('id', rowArgs.labelid)
:cssText(args.labelstyle)
:cssText(rowArgs.rowcellstyle)
:wikitext(rowArgs.label)
:done()
end
local dataCell = row:tag('td')
if not rowArgs.label then
dataCell
:attr('colspan', 2)
----:css('text-align', 'center')
end
dataCell
:attr('id', rowArgs.dataid)
:addClass(rowArgs.class)
:cssText(rowArgs.datastyle)
:cssText(rowArgs.rowcellstyle)
:wikitext(fixChildBoxes(rowArgs.data, 'td'))
end
end
local function renderTitle()
if not args.title then return end
root
:tag('caption')
:addClass(args.titleclass)
:cssText(args.titlestyle)
:wikitext(args.title)
end
local function renderAboveRow()
if not args.above then return end
root
:tag('tr')
:tag('th')
:attr('colspan', 2)
:addClass(args.aboveclass)
--:css('text-align', 'center')
--:css('font-size', '125%')
--:css('font-weight', 'bold')
:cssText(args.abovestyle)
:wikitext(fixChildBoxes(args.above,'th'))
end
local function renderBelowRow()
if not args.below then return end
root
:tag('tr')
:tag('td')
:attr('colspan', '2')
:addClass(args.belowclass)
--:css('text-align', 'center')
:cssText(args.belowstyle)
:wikitext(fixChildBoxes(args.below,'td'))
end
local function renderSubheaders()
if args.subheader then
args.subheader1 = args.subheader
end
if args.subheaderrowclass then
args.subheaderrowclass1 = args.subheaderrowclass
end
local subheadernums = getArgNums('subheader')
for k, num in ipairs(subheadernums) do
addRow({
data = args['subheader' .. tostring(num)],
datastyle = args.subheaderstyle,
rowcellstyle = args['subheaderstyle' .. tostring(num)],
class = args.subheaderclass,
rowclass = args['subheaderrowclass' .. tostring(num)]
})
end
end
local function renderImages()
if args.image then
args.image1 = args.image
end
if args.caption then
args.caption1 = args.caption
end
local imagenums = getArgNums('image')
for k, num in ipairs(imagenums) do
local caption = args['caption' .. tostring(num)]
local data = mw.html.create():wikitext(args['image' .. tostring(num)])
if caption then
data
:tag('div')
:cssText(args.captionstyle)
:wikitext(caption)
end
addRow({
data = tostring(data),
datastyle = args.imagestyle,
class = args.imageclass,
rowclass = args['imagerowclass' .. tostring(num)]
})
end
end
local function renderRows()
-- Gets the union of the header and data argument numbers,
-- and renders them all in order using addRow.
local rownums = union(getArgNums('header'), getArgNums('data'))
table.sort(rownums)
for k, num in ipairs(rownums) do
addRow({
header = args['header' .. tostring(num)],
label = args['label' .. tostring(num)],
data = args['data' .. tostring(num)],
datastyle = args.datastyle,
class = args['class' .. tostring(num)],
rowclass = args['rowclass' .. tostring(num)],
rowstyle = args['rowstyle' .. tostring(num)],
rowcellstyle = args['rowcellstyle' .. tostring(num)],
dataid = args['dataid' .. tostring(num)],
labelid = args['labelid' .. tostring(num)],
headerid = args['headerid' .. tostring(num)],
rowid = args['rowid' .. tostring(num)]
})
end
end
--local function renderNavBar()
-- if not args.name then return end
--
-- root
-- :tag('tr')
-- :tag('td')
-- :attr('colspan', '2')
-- --:css('text-align', 'right')
-- :wikitext(navbar{
-- args.name,
-- mini = 1,
-- })
--end
local function renderItalicTitle()
local italicTitle = args['italic title'] and mw.ustring.lower(args['italic title'])
if italicTitle == '' or italicTitle == 'force' or italicTitle == 'yes' then
root:wikitext(mw.getCurrentFrame():expandTemplate({title = 'italic title'}))
end
end
local function renderTrackingCategories()
if args.decat ~= 'yes' then
if args.child == 'yes' then
if args.title then
root:wikitext('[[Category:Pages which use embedded infobox templates with the title parameter]]')
end
elseif #(getArgNums('data')) == 0 and mw.title.getCurrentTitle().namespace == 0 then
root:wikitext('[[Category:Articles which use infobox templates with no data rows]]')
end
end
end
local function _infobox()
-- Specify the overall layout of the infobox, with special settings
-- if the infobox is used as a 'child' inside another infobox.
if args.child ~= 'yes' then
root = mw.html.create('table')
root
:addClass((args.subbox ~= 'yes') and 'infobox' or nil)
:addClass(args.bodyclass)
--if args.subbox == 'yes' then
--root
--:css('padding', '0')
--:css('border', 'none')
--:css('margin', '-3px')
--:css('width', 'auto')
--:css('min-width', '100%')
--:css('font-size', '100%')
--:css('clear', 'none')
--:css('float', 'none')
--:css('background-color', 'transparent')
--else
--root
--:css('width', '400px') -- Changed from 22em
--end
root
:cssText(args.bodystyle)
renderTitle()
renderAboveRow()
else
root = mw.html.create()
root
:wikitext(args.title)
end
renderSubheaders()
renderImages()
renderRows()
renderBelowRow()
--renderNavBar()
renderItalicTitle()
renderTrackingCategories()
return tostring(root) .. mw.getCurrentFrame():extensionTag{
name = 'templatestyles', args = { src = 'Module:Infobox/styles.css' }
}
end
local function preprocessSingleArg(argName)
-- If the argument exists and isn't blank, add it to the argument table.
-- Blank arguments are treated as nil to match the behaviour of ParserFunctions.
if origArgs[argName] and origArgs[argName] ~= '' then
args[argName] = origArgs[argName]
end
end
local function preprocessArgs(prefixTable, step)
-- Assign the parameters with the given prefixes to the args table, in order, in batches
-- of the step size specified. This is to prevent references etc. from appearing in the
-- wrong order. The prefixTable should be an array containing tables, each of which has
-- two possible fields, a "prefix" string and a "depend" table. The function always parses
-- parameters containing the "prefix" string, but only parses parameters in the "depend"
-- table if the prefix parameter is present and non-blank.
if type(prefixTable) ~= 'table' then
error("Non-table value detected for the prefix table", 2)
end
if type(step) ~= 'number' then
error("Invalid step value detected", 2)
end
-- Get arguments without a number suffix, and check for bad input.
for i,v in ipairs(prefixTable) do
if type(v) ~= 'table' or type(v.prefix) ~= "string" or (v.depend and type(v.depend) ~= 'table') then
error('Invalid input detected to preprocessArgs prefix table', 2)
end
preprocessSingleArg(v.prefix)
-- Only parse the depend parameter if the prefix parameter is present and not blank.
if args[v.prefix] and v.depend then
for j, dependValue in ipairs(v.depend) do
if type(dependValue) ~= 'string' then
error('Invalid "depend" parameter value detected in preprocessArgs')
end
preprocessSingleArg(dependValue)
end
end
end
-- Get arguments with number suffixes.
local a = 1 -- Counter variable.
local moreArgumentsExist = true
while moreArgumentsExist == true do
moreArgumentsExist = false
for i = a, a + step - 1 do
for j,v in ipairs(prefixTable) do
local prefixArgName = v.prefix .. tostring(i)
if origArgs[prefixArgName] then
moreArgumentsExist = true -- Do another loop if any arguments are found, even blank ones.
preprocessSingleArg(prefixArgName)
end
-- Process the depend table if the prefix argument is present and not blank, or
-- we are processing "prefix1" and "prefix" is present and not blank, and
-- if the depend table is present.
if v.depend and (args[prefixArgName] or (i == 1 and args[v.prefix])) then
for j,dependValue in ipairs(v.depend) do
local dependArgName = dependValue .. tostring(i)
preprocessSingleArg(dependArgName)
end
end
end
end
a = a + step
end
end
function p.infobox(frame)
-- If called via #invoke, use the args passed into the invoking template.
-- Otherwise, for testing purposes, assume args are being passed directly in.
if frame == mw.getCurrentFrame() then
origArgs = frame:getParent().args
else
origArgs = frame
end
-- Parse the data parameters in the same order that the old {{infobox}} did, so that
-- references etc. will display in the expected places. Parameters that depend on
-- another parameter are only processed if that parameter is present, to avoid
-- phantom references appearing in article reference lists.
preprocessSingleArg('child')
preprocessSingleArg('bodyclass')
preprocessSingleArg('subbox')
preprocessSingleArg('bodystyle')
preprocessSingleArg('title')
preprocessSingleArg('titleclass')
preprocessSingleArg('titlestyle')
preprocessSingleArg('above')
preprocessSingleArg('aboveclass')
preprocessSingleArg('abovestyle')
preprocessArgs({
{prefix = 'subheader', depend = {'subheaderstyle', 'subheaderrowclass'}}
}, 10)
preprocessSingleArg('subheaderstyle')
preprocessSingleArg('subheaderclass')
preprocessArgs({
{prefix = 'image', depend = {'caption', 'imagerowclass'}}
}, 10)
preprocessSingleArg('captionstyle')
preprocessSingleArg('imagestyle')
preprocessSingleArg('imageclass')
preprocessArgs({
{prefix = 'header'},
{prefix = 'data', depend = {'label'}},
{prefix = 'rowclass'},
{prefix = 'rowstyle'},
{prefix = 'rowcellstyle'},
{prefix = 'class'},
{prefix = 'dataid'},
{prefix = 'labelid'},
{prefix = 'headerid'},
{prefix = 'rowid'}
}, 50)
preprocessSingleArg('headerclass')
preprocessSingleArg('headerstyle')
preprocessSingleArg('labelstyle')
preprocessSingleArg('datastyle')
preprocessSingleArg('below')
preprocessSingleArg('belowclass')
preprocessSingleArg('belowstyle')
preprocessSingleArg('name')
args['italic title'] = origArgs['italic title'] -- different behaviour if blank or absent
preprocessSingleArg('decat')
return _infobox()
end
return p
2e046db27a7f61675131debae5a131a9dee12195
Template:T
10
59
117
116
2024-01-11T08:38:19Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
<includeonly><nowiki>{{</nowiki>[[Template:{{{1}}}|{{{1}}}]]{{t/piece|{{{2|---}}}}}{{t/piece|{{{3|---}}}}}{{t/piece|{{{4|---}}}}}{{t/piece|{{{5|---}}}}}{{t/piece|{{{6|---}}}}}{{t/piece|{{{7|---}}}}}{{t/piece|{{{8|---}}}}}{{t/piece|{{{9|---}}}}}{{t/piece|{{{10|---}}}}}{{t/piece|{{{11|---}}}}}{{t/piece|{{{12|---}}}}}{{t/piece|{{{13|---}}}}}{{t/piece|{{{14|---}}}}}{{t/piece|{{{15|---}}}}}{{t/piece|{{{16|---}}}}}{{t/piece|{{{17|---}}}}}{{t/piece|{{{18|---}}}}}{{t/piece|{{{19|---}}}}}{{t/piece|{{{20|---}}}}}{{t/piece|{{{21|---}}}}}<nowiki>}}</nowiki></includeonly><noinclude>
{{documentation}}</noinclude>
9bbfbb3d891ffa62ccebed3d5790ccf39d59c793
Template:T/piece
10
60
119
118
2024-01-11T08:38:20Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
{{#ifeq: {{{1|---}}}|---|||<font color="gray">''<{{{1}}}>''</font>}}<noinclude>
{{/doc}}</noinclude>
2ddf7df2334b2a1624bf213ade67ba6b68296e86
Template:Infobox/doc
10
61
121
120
2024-01-11T08:38:20Z
EvaTheServal
2
1 revision imported
wikitext
text/x-wiki
{{Documentation|fromWikipedia=true}}
<!-- EDIT TEMPLATE DOCUMENTATION BELOW THIS LINE -->
Please refer to {{t|Infobox}} on Wikipedia for more details
<noinclude></noinclude>
<includeonly>
<!-- Template catergories go here -->
[[Category:Infobox templates]]
</includeonly>
04b27574c3656318415ace03777bcc2a3c16ef74
Module:Array
828
62
123
122
2024-01-11T08:38:22Z
EvaTheServal
2
1 revision imported
Scribunto
text/plain
-- Imported from: https://runescape.wiki/w/Module:Array
local libraryUtil = require('libraryUtil')
local checkType = libraryUtil.checkType
local checkTypeMulti = libraryUtil.checkTypeMulti
---@class Array
---@operator call(any[]): Array
---@operator concat(any[]): Array
---@operator concat(number|string|function): string
---@operator unm: Array
---@operator add(number|number[]|Array): Array
---@operator sub(number|number[]|Array): Array
---@operator mul(number|number[]|Array): Array
---@operator div(number|number[]|Array): Array
---@operator pow(number|number[]|Array): Array
local Array = {
pop = table.remove
}
Array.__index = Array
setmetatable(Array, {
__index = table,
__call = function (_, arr)
return Array.new(arr)
end
})
-- function Array.__tostring(arr)
-- -- local dumpObject = require('Module:Logger').dumpObject
-- require 'log'
-- local dumpObject = dumpObject
-- local mt = getmetatable(arr)
-- setmetatable(arr, nil)
-- local str = dumpObject(arr, {clean=true, collapseLimit=100})
-- setmetatable(arr, mt)
-- return str
-- end
function Array.__concat(lhs, rhs)
if type(lhs) == 'table' and type(rhs) == 'table' then
local res = {}
for i = 1, #lhs do
res[i] = lhs[i]
end
local l = #lhs
for i = 1, #rhs do
res[i + l] = rhs[i]
end
return setmetatable(res, getmetatable(lhs) or getmetatable(rhs))
else
return tostring(lhs) .. tostring(rhs)
end
end
function Array.__unm(arr)
return Array.map(arr, function(x) return -x end)
end
---@param lhs number|number[]|Array
---@param rhs number|number[]|Array
---@param funName string
---@param opName string
---@param fun fun(lhs: number, rhs: number): number
---@return Array
local function mathTemplate(lhs, rhs, funName, opName, fun)
checkTypeMulti('Module:Array.' .. funName, 1, lhs, {'number', 'table'})
checkTypeMulti('Module:Array.' .. funName, 2, rhs, {'number', 'table'})
local res = {}
if type(lhs) == 'number' then
for i = 1, #rhs do
res[i] = fun(lhs, rhs[i])
end
elseif type(rhs) == 'number' then
for i = 1, #lhs do
res[i] = fun(lhs[i], rhs)
end
else
assert(#lhs == #rhs, string.format('Elementwise %s failed because arrays have different sizes (left: %d, right: %d)', opName, #lhs, #rhs))
for i = 1, #lhs do
res[i] = fun(lhs[i], rhs[i])
end
end
return setmetatable(res, getmetatable(lhs) or getmetatable(rhs))
end
function Array.__add(lhs, rhs)
return mathTemplate(lhs, rhs, '__add', 'addition', function(x, y) return x + y end)
end
function Array.__sub(lhs, rhs)
return mathTemplate(lhs, rhs, '__sub', 'substraction', function(x, y) return x - y end)
end
function Array.__mul(lhs, rhs)
return mathTemplate(lhs, rhs, '__mul', 'multiplication', function(x, y) return x * y end)
end
function Array.__div(lhs, rhs)
return mathTemplate(lhs, rhs, '__div', 'division', function(x, y) return x / y end)
end
function Array.__pow(lhs, rhs)
return mathTemplate(lhs, rhs, '__pow', 'exponentiation', function(x, y) return x ^ y end)
end
function Array.__eq(lhs, rhs)
if #lhs ~= #rhs then
return false
end
for i = 1, #lhs do
if lhs[i] ~= rhs[i] then
return false
end
end
return true
end
---Behaviour depends on the value of `fn`:
---* `nil` - Checks that the array doesn't contain any **false** elements.
---* `fun(elem: any, i?: integer): boolean` - Returns **true** if `fn` returns **true** for every element.
---* `number` | `table` | `boolean` - Checks that all elements in `arr` are equal to this value.
---@param arr any[]
---@param fn? any
---@return boolean
function Array.all(arr, fn)
checkType('Module:Array.all', 1, arr, 'table')
if fn == nil then fn = function(item) return item end end
if type(fn) ~= 'function' then
local val = fn
fn = function(item) return item == val end
end
local i = 1
while arr[i] ~= nil do
---@diagnostic disable-next-line: redundant-parameter
if not fn(arr[i], i) then
return false
end
i = i + 1
end
return true
end
---Behaviour depends on the value of `fn`:
---* `nil` - Checks that the array contains at least one non **false** element.
---* `fun(elem: any, i?: integer): boolean` - Returns **true** if `fn` returns **true** for at least one element.
---* `number` | `table` | `boolean` - Checks that `arr` contains this value.
---@param arr any[]
---@param fn? any
---@return boolean
function Array.any(arr, fn)
checkType('Module:Array.any', 1, arr, 'table')
if fn == nil then fn = function(item) return item end end
if type(fn) ~= 'function' then
local val = fn
fn = function(item) return item == val end
end
local i = 1
while arr[i] ~= nil do
---@diagnostic disable-next-line: redundant-parameter
if fn(arr[i], i) then
return true
end
i = i + 1
end
return false
end
---Recursively removes all metatables.
---@param arr any[]
---@return any[]
function Array.clean(arr)
checkType('Module:Array.clean', 1, arr, 'table')
for i = 1, #arr do
if type(arr[i]) == 'table' then
Array.clean(arr[i])
end
end
setmetatable(arr, nil)
return arr
end
---Make a copy of the input table. Preserves metatables.
---@generic T: any[]
---@param arr T
---@param deep? boolean # Recursively clone subtables if **true**.
---@return T
function Array.clone(arr, deep)
checkType('Module:Array.clone', 1, arr, 'table')
checkType('Module:Array.clone', 2, deep, 'boolean', true)
local res = {}
for i = 1, #arr do
if deep == true and type(arr[i]) == 'table' then
res[i] = Array.clone(arr[i], true)
else
res[i] = arr[i]
end
end
return setmetatable(res, getmetatable(arr))
end
---Check if `arr` contains `val`.
---@param arr any[]
---@param val any
---@return boolean
function Array.contains(arr, val)
checkType('Module:Array.contains', 1, arr, 'table')
for i = 1, #arr do
if arr[i] == val then
return true
end
end
return false
end
---Check if `arr` contains any of the values in the table `t`.
---@param arr any[]
---@param t any[]
---@return boolean
function Array.containsAny(arr, t)
checkType('Module:Array.containsAny', 1, arr, 'table')
checkType('Module:Array.containsAny', 2, t, 'table')
local lookupTbl = {}
for i = 1, #t do
lookupTbl[t[i]] = true
end
for i = 1, #arr do
if lookupTbl[arr[i]] then
return true
end
end
return false
end
---Check if `arr` contains all values in the table `t`.
---@param arr any[]
---@param t any[]
---@return boolean
function Array.containsAll(arr, t)
checkType('Module:Array.containsAll', 1, arr, 'table')
checkType('Module:Array.containsAll', 2, t, 'table')
local lookupTbl = {}
local l = #t
local trueCount = 0
for i = 1, l do
lookupTbl[t[i]] = false
end
for i = 1, #arr do
if lookupTbl[arr[i]] == false then
lookupTbl[arr[i]] = true
trueCount = trueCount + 1
end
if trueCount == l then
return true
end
end
return false
end
---Convolute two number arrays.
---@generic T: number[]
---@param x T
---@param y T
---@return T
function Array.convolve(x, y)
checkType('Module:Array.convolve', 1, x, 'table')
checkType('Module:Array.convolve', 2, y, 'table')
local z = {}
local xLen, yLen = #x, #y
for j = 1, (xLen + yLen - 1) do
local sum = 0
for k = math.max(1, j - yLen + 1), math.min(xLen, j) do
sum = sum + x[k] * y[j-k+1]
end
z[j] = sum
end
return setmetatable(z, getmetatable(x) or getmetatable(y))
end
---Remove **nil** values from `arr` while preserving order.
---@generic T: any[]
---@param arr T
---@return T
function Array.condenseSparse(arr)
checkType('Module:Array.condenseSparse', 1, arr, 'table')
local keys = {}
local res = {}
local l = 0
for k in pairs(arr) do
l = l + 1
keys[l] = k
end
table.sort(keys)
for i = 1, l do
res[i] = arr[keys[i]]
end
return setmetatable(res, getmetatable(arr))
end
---Behaviour depends on value of `val`:
---* `nil` - Counts the number of non **false** elements.
---* `fun(elem: any): boolean` - Count the number of times the function returned **true**.
---* `boolean` | `number` | `table` - Counts the number of times this value occurs in `arr`.
---@param arr any[]
---@param val? any
---@return integer
function Array.count(arr, val)
checkType('Module:Array.count', 1, arr, 'table')
if val == nil then val = function(item) return item end end
if type(val) ~= 'function' then
local _val = val
val = function(item) return item == _val end
end
local count = 0
for i = 1, #arr do
if val(arr[i]) then
count = count + 1
end
end
return count
end
---Differentiate the array
---@generic T: number[]
---@param arr T
---@param order number? # Oder of the differentiation. Default is 1.
---@return T # Length is `#arr - order`
function Array.diff(arr, order)
checkType('Module:Array.diff', 1, arr, 'table')
checkType('Module:Array.diff', 2, order, 'number', true)
local res = {}
for i = 1, #arr - 1 do
res[i] = arr[i+1] - arr[i]
end
if order and order > 1 then
return Array.diff(res, order - 1)
end
return setmetatable(res, getmetatable(arr))
end
---Loops over `arr` and passes each element as the first argument to `fn`. This function returns nothing.
---@param arr any[]
---@param fn fun(elem: any, i?: integer)
function Array.each(arr, fn)
checkType('Module:Array.each', 1, arr, 'table')
checkType('Module:Array.each', 2, fn, 'function')
local i = 1
while arr[i] ~= nil do
fn(arr[i], i)
i = i + 1
end
end
---Makes a copy of `arr` with only elements for which `fn` returned **true**.
---@generic T: any[]
---@param arr T
---@param fn fun(elem: any, i?: integer): boolean
---@return T
function Array.filter(arr, fn)
checkType('Module:Array.filter', 1, arr, 'table')
checkType('Module:Array.filter', 2, fn, 'function')
local r = {}
local len = 0
local i = 1
while arr[i] ~= nil do
if fn(arr[i], i) then
len = len + 1
r[len] = arr[i]
end
i = i + 1
end
return setmetatable(r, getmetatable(arr))
end
---Find the first elements for which `fn` returns **true**.
---@param arr any[]
---@param fn any # A value to look for or a function of the form `fun(elem: any, i?: integer): boolean`.
---@param default? any # Value to return if no element passes the test.
---@return any? elem # The first element that passed the test.
---@return integer? i # The index of the item that passed the test.
function Array.find(arr, fn, default)
checkType('Module:Array.find', 1, arr, 'table')
checkTypeMulti('Module:Array.find_index', 2, fn, {'function', 'table', 'number', 'boolean'})
if type(fn) ~= 'function' then
local _val = fn
fn = function(item) return item == _val end
end
local i = 1
while arr[i] ~= nil do
---@diagnostic disable-next-line: redundant-parameter
if fn(arr[i], i) then
return arr[i], i
end
i = i + 1
end
return default, nil
end
---Find the index of `val`.
---@param arr any[]
---@param val any # A value to look for or a function of the form `fun(elem: any, i?: integer): boolean`.
---@param default? any # Value to return if no element passes the test.
---@return integer?
function Array.find_index(arr, val, default)
checkType('Module:Array.find_index', 1, arr, 'table')
checkTypeMulti('Module:Array.find_index', 2, val, {'function', 'table', 'number', 'boolean'})
if type(val) ~= 'function' then
local _val = val
val = function(item) return item == _val end
end
local i = 1
while arr[i] ~= nil do
---@diagnostic disable-next-line: redundant-parameter
if val(arr[i], i) then
return i
end
i = i + 1
end
return default
end
---Extracts a subset of `arr`.
---@generic T: any[]
---@param arr T
---@param indexes integer|integer[] # Indexes of the elements.
---@return T
function Array.get(arr, indexes)
checkType('Module:Array.set', 1, arr, 'table')
checkTypeMulti('Module:Array.set', 2, indexes, {'table', 'number'})
if type(indexes) == 'number' then
indexes = {indexes}
end
local res = {}
for i = 1, #indexes do
res[i] = arr[indexes[i]]
end
return setmetatable(res, getmetatable(arr))
end
---Integrates the array. Effectively does $\left\{\sum^{n}_{start}{arr[n]} \,\Bigg|\, n \in [start, stop]\right\}$.
---@generic T: number[]
---@param arr T # number[]
---@param start? integer # Index where to start the summation. Defaults to 1.
---@param stop? integer # Index where to stop the summation. Defaults to #arr.
---@return T
function Array.int(arr, start, stop)
checkType('Module:Array.int', 1, arr, 'table')
checkType('Module:Array.int', 2, start, 'number', true)
checkType('Module:Array.int', 3, stop, 'number', true)
local res = {}
start = start or 1
stop = stop or #arr
res[1] = arr[start]
for i = 1, stop - start do
res[i+1] = res[i] + arr[start + i]
end
return setmetatable(res, getmetatable(arr))
end
---Returns an array with elements that are present in both tables.
---@generic T: any[]
---@param arr1 T
---@param arr2 T
---@return T
function Array.intersect(arr1, arr2)
checkType('Module:Array.intersect', 1, arr1, 'table')
checkType('Module:Array.intersect', 2, arr2, 'table')
local arr2Elements = {}
local res = {}
local len = 0
Array.each(arr2, function(item) arr2Elements[item] = true end)
Array.each(arr1, function(item)
if arr2Elements[item] then
len = len + 1
res[len] = item
end
end)
return setmetatable(res, getmetatable(arr1) or getmetatable(arr2))
end
---Checks if the two inputs have at least one element in common.
---@param arr1 any[]
---@param arr2 any[]
---@return boolean
function Array.intersects(arr1, arr2)
checkType('Module:Array.intersects', 1, arr1, 'table')
checkType('Module:Array.intersects', 2, arr2, 'table')
local small = {}
local large
if #arr1 <= #arr2 then
Array.each(arr1, function(item) small[item] = true end)
large = arr2
else
Array.each(arr2, function(item) small[item] = true end)
large = arr1
end
return Array.any(large, function(item) return small[item] end)
end
---Inserts values into `arr`.
---@generic T: any[]
---@param arr T
---@param val any # If `val` is an array and `unpackVal` is **true** then the individual elements of `val` are inserted.
---@param index? integer # Location to start the insertion. Default is at the end of `arr`.
---@param unpackVal? boolean # Default is **false**.
---@return T
---@overload fun(arr: T, val: any, unpackVal: boolean): T
function Array.insert(arr, val, index, unpackVal)
checkType('Module:Array.insert', 1, arr, 'table')
checkTypeMulti('Module:Array.insert', 3, index, {'number', 'boolean', 'nil'})
checkType('Module:Array.insert', 4, unpackVal, 'boolean', true)
if type(index) == 'boolean' then
unpackVal, index = index, nil
end
local len = #arr
index = index or (len + 1)
local mt = getmetatable(arr)
setmetatable(arr, nil)
if type(val) == 'table' and unpackVal then
local len2 = #val
for i = 0, len - index do
arr[len + len2 - i] = arr[len - i]
end
for i = 0, len2 - 1 do
arr[index + i] = val[i + 1]
end
else
table.insert(arr, index, val)
end
return setmetatable(arr, mt)
end
---Returns the last element of `arr`.
---@param arr any[]
---@param offset? integer
---@return any
function Array.last(arr, offset)
checkType('Module:Array.last', 1, arr, 'table')
checkType('Module:Array.last', 2, offset, 'number', true)
return arr[#arr + offset]
end
---Returns a new table were each element of `arr` is modified by `fn`.
---@generic T: any[]
---@param arr T
---@param fn fun(elem: any, i?: integer): any # First argument is the current element, the second argument is the index of the current element.
---@return T
function Array.map(arr, fn)
checkType('Module:Array.map', 1, arr, 'table')
checkType('Module:Array.map', 2, fn, 'function')
local len = 0
local r = {}
local i = 1
while arr[i] ~= nil do
local tmp = fn(arr[i], i)
if tmp ~= nil then
len = len + 1
r[len] = tmp
end
i = i + 1
end
return setmetatable(r, getmetatable(arr))
end
---Find the element for which `fn` returned the largest value.
---@param arr any[]
---@param fn fun(elem: any): any # The returned value needs to be comparable using the `<` operator.
---@return any elem # The element with the largest `fn` value.
---@return integer i # The index of this element.
function Array.max_by(arr, fn)
checkType('Module:Array.max_by', 1, arr, 'table')
checkType('Module:Array.max_by', 2, fn, 'function')
return unpack(Array.reduce(arr, function(new, old, i)
local y = fn(new)
return y > old[2] and {new, y, i} or old
end, {nil, -math.huge}))
end
---Find the largest value in the array.
---@param arr any[] # The values need to be comparable using the `<` operator.
---@return any elem
---@return integer i # The index of the largest value.
function Array.max(arr)
checkType('Module:Array.max', 1, arr, 'table')
local val, _, i = Array.max_by(arr, function(x) return x end)
return val, i
end
---Find the smallest value in the array.
---@param arr any[] # The values need to be comparable using the `<` operator.
---@return any elem
---@return integer i # The index of the smallest value.
function Array.min(arr)
checkType('Module:Array.min', 1, arr, 'table')
local val, _, i = Array.max_by(arr, function(x) return -x end)
return val, i
end
---Turn the input table into an Array. This makes it possible to use the colon `:` operator to access the Array methods.
---
---It also enables the use of math operators with the array.
---```
---local x = arr.new{ 1, 2, 3 }
---local y = arr{ 4, 5, 6 } -- Alternative notation
---
---print( -x ) --> { -1, -2, -3 }
---print( x + 2 ) --> { 3, 4, 5 }
---print( x - 2 ) --> { -1, 0, 1 }
---print( x * 2 ) --> { 2, 4, 6 }
---print( x / 2 ) --> { 0.5, 1, 1.5 }
---print( x ^ 2 ) --> { 1, 4, 9 }
---
---print( x + y ) --> { 5, 7, 9 }
---print( x .. y ) --> { 1, 2, 3, 4, 5, 6 }
---print( (x .. y):reject{3, 4, 5} ) --> { 1, 2, 6 }
---print( x:sum() ) --> 6
---
---print( x:update( {1, 3}, y:get{2, 3} * 2 ) ) --> { 10, 2, 12 }
---```
---@param arr? any[]
---@return Array
function Array.new(arr)
local obj = arr or {}
for _, v in pairs(obj) do
if type(v) == 'table' then
Array.new(v)
end
end
if getmetatable(obj) == nil then
setmetatable(obj, Array)
end
return obj
end
---Creates an object that returns a value that is `step` higher than the previous value each time it gets called.
---
---The stored value can be read without incrementing by reading the `val` field.
---
---A new stored value can be set through the `val` field.
---
---A new step size can be set through the `step` field.
---```
---local inc = arr.newIncrementor(10, 5)
---print( inc() ) --> 10
---print( inc() ) --> 15
---print( inc.val ) --> 15
---inc.val = 100
---inc.step = 20
---print( inc.val ) --> 100
---print( inc() ) --> 120
---```
---@param start? number # Default is 1.
---@param step? number # Default is 1.
---@return Incrementor
function Array.newIncrementor(start, step)
checkType('Module:Array.newIncrementor', 1, start, 'number', true)
checkType('Module:Array.newIncrementor', 2, step, 'number', true)
step = step or 1
local n = (start or 1) - step
---@class Incrementor
local obj = {}
return setmetatable(obj, {
__call = function() n = n + step return n end,
__tostring = function() return n end,
__index = function() return n end,
__newindex = function(self, k, v)
if k == 'step' and type(v) == 'number' then
step = v
elseif type(v) == 'number' then
n = v
end
end,
__concat = function(x, y) return tostring(x) .. tostring(y) end
})
end
---Returns a range of numbers.
---@param start number # Start value inclusive.
---@param stop number # Stop value inclusive for integers, exclusive for floats.
---@param step? number # Default is 1.
---@return Array
---@overload fun(stop: number): Array
function Array.range(start, stop, step)
checkType('Module:Array.range', 1, start, 'number')
checkType('Module:Array.range', 2, stop, 'number', true)
checkType('Module:Array.range', 3, step, 'number', true)
local arr = {}
local len = 0
if not stop then
stop = start
start = 1
end
for i = start, stop, step or 1 do
len = len + 1
arr[len] = i
end
return setmetatable(arr, Array)
end
---Condenses the array into a single value.
---
---For each element `fn` is called with the current element, the current accumulator, and the current element index. The returned value of `fn` becomes the accumulator for the next element.
---
---If no `accumulator` value is given at the start then the first element off `arr` becomes the accumulator and the iteration starts from the second element.
---```
---local t = { 1, 2, 3, 4 }
---local sum = arr.reduce( t, function(elem, acc) return acc + elem end ) -- sum == 10
---```
---@param arr any[]
---@param fn fun(elem: any, acc: any, i?: integer): any # The result of this function becomes the `acc` for the next element.
---@param accumulator? any
---@return any # This is the last accumulator value.
function Array.reduce(arr, fn, accumulator)
checkType('Module:Array.reduce', 1, arr, 'table')
checkType('Module:Array.reduce', 2, fn, 'function')
local acc = accumulator
local i = 1
if acc == nil then
acc = arr[1]
i = 2
end
while arr[i] ~= nil do
acc = fn(arr[i], acc, i)
i = i + 1
end
return acc
end
---Make a copy off `arr` with certain values removed.
---
---Behaviour for different values of `val`:
---* `boolean` | `number` - Remove values equal to this.
---* `table` - Remove all values in this table.
---* `fun(elem: any, i?: integer): boolean` - Remove elements for which the functions returns **true**.
---@generic T: any[]
---@param arr T
---@param val table|function|number|boolean
---@return T
function Array.reject(arr, val)
checkType('Module:Array.reject', 1, arr, 'table')
checkTypeMulti('Module:Array.reject', 2, val, {'function', 'table', 'number', 'boolean'})
if type(val) ~= 'function' and type(val) ~= 'table' then
val = {val}
end
local r = {}
local len = 0
if type(val) == 'function' then
local i = 1
while arr[i] ~= nil do
if not val(arr[i], i) then
len = len + 1
r[len] = arr[i]
end
i = i + 1
end
else
local rejectMap = {}
Array.each(val --[[@as any[] ]], function(item) rejectMap[item] = true end)
local i = 1
while arr[i] ~= nil do
if not rejectMap[arr[i]] then
len = len + 1
r[len] = arr[i]
end
i = i + 1
end
end
return setmetatable(r, getmetatable(arr))
end
---Returns an Array with `val` repeated `n` times.
---@param val any
---@param n integer
---@return Array
function Array.rep(val, n)
checkType('Module:Array.rep', 2, n, 'number')
local r = {}
for i = 1, n do
r[i] = val
end
return setmetatable(r, Array)
end
---Condenses the array into a single value while saving every accumulator value.
---
---For each element `fn` is called with the current element, the current accumulator, and the current element index. The returned value of `fn` becomes the accumulator for the next element.
---
---If no `accumulator` value is given at the start then the first element off `arr` becomes the accumulator and the iteration starts from the second element.
---```
---local t = { 1, 2, 3, 4 }
---local x = arr.scan( t, function(elem, acc) return acc + elem end ) -- x = { 1, 3, 6, 10 }
---```
---@generic T: any[]
---@param arr T
---@param fn fun(elem: any, acc: any, i?: integer): any # Returned value becomes the accumulator for the next element.
---@param accumulator? any
---@return T
function Array.scan(arr, fn, accumulator)
checkType('Module:Array.scan', 1, arr, 'table')
checkType('Module:Array.scan', 2, fn, 'function')
local acc = accumulator
local r = {}
local i = 1
while arr[i] ~= nil do
if i == 1 and not accumulator then
acc = arr[i]
else
acc = fn(arr[i], acc, i)
end
r[i] = acc
i = i + 1
end
return setmetatable(r, getmetatable(arr))
end
---Update a range of index with a range of values.
---
---If if only one value is given but multiple indexes than that value is set for all those indexes.
---
---If `values` is a table then it must of the same length as `indexes`.
---@generic T: any[]
---@param arr T
---@param indexes integer|integer[]
---@param values any|any[]
---@return T
function Array.set(arr, indexes, values)
checkType('Module:Array.set', 1, arr, 'table')
checkTypeMulti('Module:Array.set', 2, indexes, {'table', 'number'})
local mt = getmetatable(arr)
setmetatable(arr, nil)
if type(indexes) == 'number' then
indexes = {indexes}
end
if type(values) == 'table' then
assert(#indexes == #values, string.format("Module:Array.set: 'indexes' and 'values' arrays are not equal length (#indexes = %d, #values = %d)", #indexes, #values))
for i = 1, #indexes do
arr[indexes[i]] = values[i]
end
else
for i = 1, #indexes do
arr[indexes[i]] = values
end
end
return setmetatable(arr, mt)
end
---Extract a subtable from `arr`.
---@generic T: any[]
---@param arr T
---@param start integer # Start index. Use negative values to count form the end of the array.
---@param stop integer # Stop index. Use negative values to count form the end of the array.
---@return T
---@overload fun(arr: T, stop: integer): T
function Array.slice(arr, start, stop)
checkType('Module:Array.slice', 1, arr, 'table')
checkType('Module:Array.slice', 2, start, 'number', true)
checkType('Module:Array.slice', 3, stop, 'number', true)
start = start or #arr
if start < 0 then
start = #arr + start
end
if stop == nil then
stop = start
start = 1
end
if stop < 0 then
stop = #arr + stop
end
local r = {}
local len = 0
for i = start, stop do
len = len + 1
r[len] = arr[i]
end
return setmetatable(r, getmetatable(arr))
end
---Split `arr` into two arrays.
---@generic T: any[]
---@param arr T
---@param index integer # Index to split on.
---@return T x # [1, index]
---@return T y # [index + 1, #arr]
function Array.split(arr, index)
checkType('Module:Array.split', 1, arr, 'table')
checkType('Module:Array.split', 2, index, 'number')
local x = {}
local y = {}
for i = 1, #arr do
table.insert(i <= index and x or y, arr[i])
end
return setmetatable(x, getmetatable(arr)), setmetatable(y, getmetatable(arr))
end
---Returns the sum of all elements of `arr`.
---@param arr number[]
---@return number
function Array.sum(arr)
checkType('Module:Array.sum', 1, arr, 'table')
local res = 0
for i = 1, #arr do
res = res + arr[i]
end
return res
end
---Extract a subtable from `arr`.
---@generic T: any[]
---@param arr T
---@param count integer # Length of the subtable.
---@param start? integer # Start index. Default is 1.
---@return T
function Array.take(arr, count, start)
checkType('Module:Array.take', 1, arr, 'table')
checkType('Module:Array.take', 2, count, 'number')
checkType('Module:Array.take', 3, start, 'number', true)
local x = {}
start = start or 1
for i = start, math.min(#arr, count + start - 1) do
table.insert(x, arr[i])
end
return setmetatable(x, getmetatable(arr))
end
---Extract a subtable from `arr`.
---```
---local t = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }
---local x = arr.take_every( t, 2 ) --> x = { 1, 3, 5, 7, 9 }
---local x = arr.take_every( t, 2, 3 ) --> x = { 1, 3, 5 }
---local x = arr.take_every( t, 2, 3, 2 ) --> x = { 2, 4, 6 }
--- ```
---@generic T: any[]
---@param arr T
---@param n integer # Step size.
---@param start? integer # Start index.
---@param count? integer # Max amount of elements to get.
---@return T
function Array.take_every(arr, n, start, count)
checkType('Module:Array.take_every', 1, arr, 'table')
checkType('Module:Array.take_every', 2, n, 'number')
checkType('Module:Array.take_every', 3, start, 'number', true)
checkType('Module:Array.take_every', 4, count, 'number', true)
count = count or #arr
local r = {}
local len = 0
local i = start or 1
while arr[i] ~= nil and len < count do
len = len + 1
r[len] = arr[i]
i = i + n
end
return setmetatable(r, getmetatable(arr))
end
---Return a new table with all duplicates removed.
---@generic T: any[]
---@param arr T
---@param fn? fun(elem: any): any # Function to generate an id for each element. The result will then contain elements that generated unique ids.
---@return T
function Array.unique(arr, fn)
checkType('Module:Array.unique', 1, arr, 'table')
checkType('Module:Array.unique', 2, fn, 'function', true)
fn = fn or function(item) return item end
local r = {}
local len = 0
local hash = {}
local i = 1
while arr[i] ~= nil do
local id = fn(arr[i])
if not hash[id] then
len = len + 1
r[len] = arr[i]
hash[id] = true
end
i = i + 1
end
return setmetatable(r, getmetatable(arr))
end
---Combine elements with the same index from multiple arrays.
---```
---local x = {1, 2, 3}
---local y = {4, 5, 6, 7}
---local z = arr.zip( x, y ) --> z = { { 1, 4 }, { 2, 5 }, { 3, 6 }, { 7 } }
---```
---@param ... any[]
---@return Array
function Array.zip(...)
local arrs = { ... }
checkType('Module:Array.zip', 1, arrs[1], 'table')
local r = {}
local _, longest = Array.max_by(arrs, function(arr) return #arr end)
for i = 1, longest do
local q = {}
for j = 1, #arrs do
table.insert(q, arrs[j][i])
end
table.insert(r, setmetatable(q, Array))
end
return setmetatable(r, Array)
end
-- Range indexing has a performance impact so this is placed in a separate subclass
Array.RI_mt = {}
for k, v in pairs(Array) do
Array.RI_mt[k] = v
end
function Array.RI_mt.__index(t, k)
if type(k) == 'table' then
local res = {}
for i = 1, #k do
res[i] = t[k[i]]
end
return setmetatable(res, Array)
else
return Array[k]
end
end
function Array.RI_mt.__newindex(t, k, v)
if type(k) == 'table' then
if type(v) == 'table' then
for i = 1, #k do
t[k[i]] = v[i]
end
else
for i = 1, #k do
t[k[i]] = v
end
end
else
rawset(t, k, v)
end
end
---Enable range indexing on the input array.
---
---This has a performance impact on reads and writes to the table.
---```
---local t = arr{10, 11, 12, 13, 14, 15}:ri()
---print( t[{2, 3}] ) --> { 11, 12 }
---```
---@param arr any[]
---@param recursive? boolean # Default is false.
---@return Array
function Array.ri(arr, recursive)
checkType('Module:Array.ri', 1, arr, 'table')
checkType('Module:Array.ri', 2, recursive, 'boolean', true)
arr = arr or {}
if recursive then
for _, v in pairs(arr) do
if type(v) == 'table' then
Array.ri(v, true)
end
end
end
if getmetatable(arr) == nil or getmetatable(arr) == Array then
setmetatable(arr, Array.RI_mt)
end
return arr
end
---Globally enable range indexing on all Array objects by default.
---@param set boolean
function Array.allwaysAllowRangeIndexing(set)
checkType('Module:Array.allwaysAllowRangeIndexing', 1, set, 'boolean')
if set then
Array.__index = Array.RI_mt.__index
Array.__newindex = Array.RI_mt.__newindex
else
Array.__index = Array
Array.__newindex = nil
end
end
return Array
c81adb59b4d3a4728952df3ad8d681664333a799
Module:Format link
828
63
125
124
2024-01-11T08:38:23Z
EvaTheServal
2
1 revision imported
Scribunto
text/plain
-- Imported from: https://en.wikipedia.org/wiki/Module:Format_link
--------------------------------------------------------------------------------
-- Format link
--
-- Makes a wikilink from the given link and display values. Links are escaped
-- with colons if necessary, and links to sections are detected and displayed
-- with " § " as a separator rather than the standard MediaWiki "#". Used in
-- the {{format link}} template.
--------------------------------------------------------------------------------
local libraryUtil = require('libraryUtil')
local checkType = libraryUtil.checkType
local checkTypeForNamedArg = libraryUtil.checkTypeForNamedArg
local mArguments -- lazily initialise [[Module:Arguments]]
local mError -- lazily initialise [[Module:Error]]
local yesno -- lazily initialise [[Module:Yesno]]
local p = {}
--------------------------------------------------------------------------------
-- Helper functions
--------------------------------------------------------------------------------
local function getArgs(frame)
-- Fetches the arguments from the parent frame. Whitespace is trimmed and
-- blanks are removed.
mArguments = require('Module:Arguments')
return mArguments.getArgs(frame, {parentOnly = true})
end
local function removeInitialColon(s)
-- Removes the initial colon from a string, if present.
return s:match('^:?(.*)')
end
local function maybeItalicize(s, shouldItalicize)
-- Italicize s if s is a string and the shouldItalicize parameter is true.
if s and shouldItalicize then
return '<i>' .. s .. '</i>'
else
return s
end
end
local function parseLink(link)
-- Parse a link and return a table with the link's components.
-- These components are:
-- - link: the link, stripped of any initial colon (always present)
-- - page: the page name (always present)
-- - section: the page name (may be nil)
-- - display: the display text, if manually entered after a pipe (may be nil)
link = removeInitialColon(link)
-- Find whether a faux display value has been added with the {{!}} magic
-- word.
local prePipe, display = link:match('^(.-)|(.*)$')
link = prePipe or link
-- Find the page, if it exists.
-- For links like [[#Bar]], the page will be nil.
local preHash, postHash = link:match('^(.-)#(.*)$')
local page
if not preHash then
-- We have a link like [[Foo]].
page = link
elseif preHash ~= '' then
-- We have a link like [[Foo#Bar]].
page = preHash
end
-- Find the section, if it exists.
local section
if postHash and postHash ~= '' then
section = postHash
end
return {
link = link,
page = page,
section = section,
display = display,
}
end
local function formatDisplay(parsed, options)
-- Formats a display string based on a parsed link table (matching the
-- output of parseLink) and an options table (matching the input options for
-- _formatLink).
local page = maybeItalicize(parsed.page, options.italicizePage)
local section = maybeItalicize(parsed.section, options.italicizeSection)
if (not section) then
return page
elseif (not page) then
return mw.ustring.format('§ %s', section)
else
return mw.ustring.format('%s § %s', page, section)
end
end
local function missingArgError(target)
mError = require('Module:Error')
return mError.error{message =
'Error: no link or target specified! ([[' .. target .. '#Errors|help]])'
}
end
--------------------------------------------------------------------------------
-- Main functions
--------------------------------------------------------------------------------
function p.formatLink(frame)
-- The formatLink export function, for use in templates.
yesno = require('Module:Yesno')
local args = getArgs(frame)
local link = args[1] or args.link
local target = args[3] or args.target
if not (link or target) then
return missingArgError('Template:Format link')
end
return p._formatLink{
link = link,
display = args[2] or args.display,
target = target,
italicizePage = yesno(args.italicizepage),
italicizeSection = yesno(args.italicizesection),
categorizeMissing = args.categorizemissing
}
end
function p._formatLink(options)
-- The formatLink export function, for use in modules.
checkType('_formatLink', 1, options, 'table')
local function check(key, expectedType) --for brevity
checkTypeForNamedArg(
'_formatLink', key, options[key], expectedType or 'string', true
)
end
check('link')
check('display')
check('target')
check('italicizePage', 'boolean')
check('italicizeSection', 'boolean')
check('categorizeMissing')
-- Normalize link and target and check that at least one is present
if options.link == '' then options.link = nil end
if options.target == '' then options.target = nil end
if not (options.link or options.target) then
return missingArgError('Module:Format link')
end
local parsed = parseLink(options.link)
local display = options.display or parsed.display
local catMissing = options.categorizeMissing
local category = ''
-- Find the display text
if not display then display = formatDisplay(parsed, options) end
-- Handle the target option if present
if options.target then
local parsedTarget = parseLink(options.target)
parsed.link = parsedTarget.link
parsed.page = parsedTarget.page
end
-- Test if page exists if a diagnostic category is specified
if catMissing and (mw.ustring.len(catMissing) > 0) then
local title = nil
if parsed.page then title = mw.title.new(parsed.page) end
if title and (not title.isExternal) then
local success, exists = pcall(function() return title.exists end)
if success and not exists then
category = mw.ustring.format('[[Category:%s]]', catMissing)
end
end
end
-- Format the result as a link
if parsed.link == display then
return mw.ustring.format('[[:%s]]%s', parsed.link, category)
else
return mw.ustring.format('[[:%s|%s]]%s', parsed.link, display, category)
end
end
--------------------------------------------------------------------------------
-- Derived convenience functions
--------------------------------------------------------------------------------
function p.formatPages(options, pages)
-- Formats an array of pages using formatLink and the given options table,
-- and returns it as an array. Nil values are not allowed.
local ret = {}
for i, page in ipairs(pages) do
ret[i] = p._formatLink{
link = page,
categorizeMissing = options.categorizeMissing,
italicizePage = options.italicizePage,
italicizeSection = options.italicizeSection
}
end
return ret
end
return p
410e1254e813fed6fe2f04598836316a197db2d1
Module:Infobox/styles.css
828
64
127
126
2024-01-11T08:38:24Z
EvaTheServal
2
1 revision imported
text
text/plain
.infobox {
/* In case if tooltips go out of boundary */
overflow: visible;
width: 100%;
max-width: 400px;
margin-top: 0;
margin-bottom: var( --space-md );
background: var( --color-surface-2 );
border-radius: var( --border-radius--medium );
border-spacing: 0;
font-size: 0.875rem;
text-align: left;
display: block;
}
/* Table elements */
.infobox tbody {
display: flex;
flex-wrap: wrap;
}
.infobox tr {
display: flex;
box-sizing: border-box;
flex-direction: column;
padding: 0 10px;
margin-top: 10px;
}
.infobox th,
.infobox td {
padding: 0 5px;
}
/* Infobox column */
.infobox .infobox-nocol {
width: 100%;
flex-direction: row;
}
.infobox .infobox-nocol th {
width: 30%;
}
.infobox .infobox-nocol td {
width: 70%;
}
.infobox .infobox-col1 {
width: 100%;
}
.infobox .infobox-col2 {
width: 50%;
}
.infobox .infobox-col3 {
width: calc( 100% / 3 );
}
.infobox .infobox-col4 {
width: 25%;
}
.infobox-data {
min-width: 25%;
}
/* Infobox image */
.infobox .infobox-image {
overflow: hidden;
padding: 0;
margin-top: 0;
border-radius: var( --border-radius--medium ) var( --border-radius--medium ) 0 0;
}
.infobox-image td {
padding: 0;
}
.infobox-image--light .image {
background: #eaecf0;
}
.infobox-image--dark .image {
background: #2b2f36;
}
.infobox-image .image:hover img {
transform: scale( 1.1 );
}
.infobox-image img {
display: block;
max-width: 100%;
background: var( --background-color-quiet--hover );
}
/* Neutral background for all transprent SVG */
.infobox-image img[ src$='.svg' ] {
background: #eaecf0;
}
/* Infobox title */
.infobox .infobox-title {
width: 100%;
margin-top: 20px;
margin-bottom: 5px;
color: var( --color-base--emphasized );
font-size: var( --font-size-h3 );
line-height: var( --line-height-xs );
}
/* Infobox indicator */
.infobox .infobox-indicator {
margin-top: 0;
padding: 0;
}
/* Infobox subtitle */
.infobox .infobox-subtitle {
/* Cancel infobox-title bottom margin */
margin-top: -5px;
margin-bottom: 5px;
}
.infobox .infobox-indicator th,
.infobox .infobox-subtitle th {
display: none;
}
/* Infobox header */
.infobox .infobox-header {
width: 100%;
padding-top: 15px;
border-top: 1px solid;
border-color: var( --border-color-base );
margin-top: 15px;
color: var( --color-base--emphasized );
line-height: var( --line-height-xs );
font-size: 1rem;
}
/* Infobox value */
.infobox-data th {
color: var( --color-base--subtle );
font-size: 0.8125rem;
font-weight: normal;
letter-spacing: 0.75px;
}
.infobox-data td {
font-weight: 600;
}
.infobox-data ul,
.infobox-data ol {
margin-top: 0;
}
/* Infobox button */
.infobox .infobox-button-bar {
width: 100%;
padding: 0;
margin-top: 25px;
text-align: center;
}
.infobox-button-bar th {
padding: 0;
}
/* Collapsible toggle */
.infobox tr:first-of-type .mw-collapsible-toggle {
position: relative;
display: none;
float: none;
}
.infobox tr:first-of-type .mw-collapsible-toggle .mw-collapsible-text {
position: absolute;
right: 0;
display: block;
padding: 5px 15px;
background: var( --color-destructive );
border-radius: 0 var( --border-radius--medium );
color: #fff;
}
.infobox tr:first-of-type .mw-collapsible-toggle .mw-collapsible-text:hover {
background: var( --color-destructive--hover );
}
.infobox tr:first-of-type .mw-collapsible-toggle .mw-collapsible-text:active {
background: var( --color-destructive--active );
}
.infobox tr:first-of-type .mw-collapsible-toggle-collapsed .mw-collapsible-text {
background: var( --color-primary );
}
.infobox tr:first-of-type .mw-collapsible-toggle-collapsed .mw-collapsible-text:hover {
background: var( --color-primary--hover );
}
.infobox tr:first-of-type .mw-collapsible-toggle-collapsed .mw-collapsible-text:active {
background: var( --color-primary--active );
}
.infobox tr:first-of-type .mw-collapsible-toggle:before,
.infobox tr:first-of-type .mw-collapsible-toggle:after {
content: none;
}
@media only screen and ( max-width: 720px ) {
.infobox {
margin-right: auto;
margin-left: auto;
}
.infobox tr:first-of-type .mw-collapsible-toggle {
display: block;
}
}
754ac9608eeaef9b15784d251643ea8c0a01b58e
Module:User error
828
65
129
128
2024-01-11T08:38:25Z
EvaTheServal
2
1 revision imported
Scribunto
text/plain
--------------------------------------------------------------------------------
-- A less intimidating version of the built-in "error()" function, to help
-- editors fix their mistakes when transcluding a template.
--
-- @see [[wikia:w:c:Dev:Module:User error]] for a similar module.
--------------------------------------------------------------------------------
local checkType = require("libraryUtil").checkType;
return function (message, ...)
checkType("Module:User error", 1, message, "string");
local result = mw.text.tag(
"strong",
{ class="error" },
"Error: " .. message
);
local categories = {};
for i = 1, select("#", ...) do
local category = select(i, ...);
checkType("Module:User error", 1 + i, category, "string", true);
if (category and category ~= "") then
table.insert(categories, "[[Category:" .. category .. "]]");
end
end
return result .. table.concat(categories);
end;
a4101fc46477bcd3c5dd899b157bf34b216d820f
Module:Mbox
828
66
131
130
2024-01-11T08:38:25Z
EvaTheServal
2
1 revision imported
Scribunto
text/plain
local libraryUtil = require( 'libraryUtil' )
local checkType = libraryUtil.checkType
local mArguments -- lazily initialise [[Module:Arguments]]
local mError -- lazily initialise [[Module:Error]]
local p = {}
--- Helper function to throw error
--
-- @param msg string - Error message
--
-- @return string - Formatted error message in wikitext
local function makeWikitextError( msg )
mError = require( 'Module:Error' )
return mError.error{
message = 'Error: ' .. msg .. '.'
}
end
function p.mbox( frame )
local args = getArgs( frame )
local title = args[1] or args[ 'title' ]
local text = args[2] or args[ 'text' ]
if not s then
return p.makeWikitextError(
'no text specified',
'Template:Mbox#Errors',
args.category
)
end
return p._mbox( title, text, {
extraclasses = args.extraclasses,
icon = args.icon
} )
end
function p._mbox( title, text, options )
checkType( '_mbox', 1, title, 'string' )
checkType( '_mbox', 2, text, 'string' )
checkType( '_mbox', 3, options, 'table', true )
options = options or {}
local mbox = mw.html.create( 'div' )
local extraclasses
if type( options.extraclasses ) == 'string' then
extraclasses = options.extraclasses
end
mbox
:attr( 'role', 'presentation' )
:addClass( 'mbox' )
:addClass( extraclasses )
local mboxTitle = mbox:tag( 'div' ):addClass( 'mbox-title' )
if options.icon and type( options.icon ) == 'string' then
mboxTitle:tag( 'div' )
:addClass( 'mbox-icon metadata' )
:wikitext( '[[File:' .. options.icon .. '|14px|link=]]' )
:done()
:tag( 'div' )
:wikitext( title )
else
mboxTitle:wikitext( title )
end
mbox:tag( 'div' )
:addClass( 'mbox-text' )
:wikitext( text )
return mw.getCurrentFrame():extensionTag{
name = 'templatestyles', args = { src = 'Module:Mbox/styles.css' }
} .. tostring(mbox)
end
return p
3ac408bcf509952e70b97e64cb1062fe21f6c4bf
Module:Mbox/styles.css
828
67
133
132
2024-01-11T08:38:26Z
EvaTheServal
2
1 revision imported
text
text/plain
.mbox {
position: relative;
display: flex;
flex-direction: column;
margin-top: var( --space-xs );
margin-bottom: var( --space-md );
background-color: var( --color-surface-2 );
border-radius: var( --border-radius--medium );
color: var( --color-base--subtle );
font-size: 0.875rem;
line-height: var( --line-height-xs );
}
.mbox.mbox-high {
/* FIXME: Update back to Citzen CSS var when patched */
background-color: rgba( 221, 51, 51, 0.1 );
}
.mbox.mbox-med {
/* FIXME: Update back to Citzen CSS var when patched */
background-color: rgba( 255, 204, 51, 0.1 );
}
.mbox-title {
display: flex;
align-items: center;
padding: var( --space-sm ) var( --space-md );
}
.mbox-icon img {
width: 14px;
height: auto;
margin-right: var( --space-xs );
opacity: 0.5;
}
.mbox-text {
position: absolute;
top: 100%;
z-index: 10;
padding: var( --space-md );
width: 100%;
box-sizing: border-box;
background-color: var( --color-surface-1 );
border-bottom-left-radius: var( --border-radius--medium );
border-bottom-right-radius: var( --border-radius--medium );
box-shadow: var( --box-shadow-dialog );
opacity: 0;
visibility: hidden;
}
.mbox:hover {
/* Merge with popup */
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
box-shadow: var( --box-shadow-dialog );
}
.mbox:hover .mbox-text {
opacity: 1;
visibility: visible;
}
/* Dark mode */
html.skin-citizen-dark .mbox-icon img {
filter: invert( 1 );
}
6e8c0951d8f9dcde54a751e8564916bec21071ce